Every once in a while I need to convert objects of an unknown type into a known type; sometimes these types are only known at run time. In most cases I want the code to stay easy to read, so I don’t want to if-then-else the readybility of my code away.
Over the time, I have created a helper that performs the conversion in a convenient and fast way. Use it if you like.
using System; using System.Collections.Generic; using System.ComponentModel; using System.Globalization; namespace MunirHusseini { public static class Conversion { /// <summary> /// Gets the specified property value and converts it, if necessary. /// </summary> /// <typeparam name="T">The type to convert to.</typeparam> /// <param name="o">The object to convert.</param> /// <param name="defaultValue">The default value.</param> /// <returns></returns> public static T Convert<T>(this object o, T defaultValue = default) { if (o == null) return defaultValue; o = o.Convert(typeof(T), defaultValue); return o is T o1 ? o1 : defaultValue; } /// <summary> /// Gets the specified property value and converts it, if necessary. /// </summary> /// <param name="o">The object to convert.</param> /// <param name="type">The type to convert to.</param> /// <param name="defaultValue">The default value.</param> /// <returns></returns> public static object Convert(this object o, Type type, object defaultValue) { if (o == null || o is DBNull) return defaultValue; if (type.IsInstanceOfType(o)) return o; try { if (o is string s) { if (string.IsNullOrWhiteSpace(s)) return defaultValue; var result = Parse(type, s); if (result != null) return result; } var tc = TypeDescriptor.GetConverter(o.GetType()); return tc.CanConvertTo(type) ? tc.ConvertTo(o, type) : Parse(type, o) ?? defaultValue; } catch { return Parse(type, o.ToString()) ?? defaultValue; } } /// <summary> /// Parses the specified object into the specified type. /// </summary> /// <param name="type">The type to parse into.</param> /// <param name="o">The object to parse.</param> /// <returns>An object of the specified type, if successful; otherwise, null.</returns> public static object Parse(Type type, object o) { var text = o?.ToString(); return string.IsNullOrWhiteSpace(text) ? default(object) : type.Name switch { "UInt16" when ushort.TryParse(text, NumberStyles.Any, CultureInfo.InvariantCulture, out var v2) => v2, "UInt32" when uint.TryParse(text, NumberStyles.Any, CultureInfo.InvariantCulture, out var v2) => v2, "UInt64" when ulong.TryParse(text, NumberStyles.Any, CultureInfo.InvariantCulture, out var v2) => v2, "Int16" when short.TryParse(text, NumberStyles.Any, CultureInfo.InvariantCulture, out var v2) => v2, "Int32" when int.TryParse(text, NumberStyles.Any, CultureInfo.InvariantCulture, out var v2) => v2, "Int64" when long.TryParse(text, NumberStyles.Any, CultureInfo.InvariantCulture, out var v2) => v2, "Byte" when byte.TryParse(text, NumberStyles.Any, CultureInfo.InvariantCulture, out var v2) => v2, "Decimal" when decimal.TryParse(text, NumberStyles.Any, CultureInfo.InvariantCulture, out var v2) => v2, "DateTime" when DateTime.TryParse(text, CultureInfo.InvariantCulture, DateTimeStyles.AllowInnerWhite | DateTimeStyles.AllowLeadingWhite | DateTimeStyles.AllowTrailingWhite | DateTimeStyles.AllowWhiteSpaces, out var v2) => v2, "DateTimeOffset" when DateTimeOffset.TryParse(text, CultureInfo.InvariantCulture, DateTimeStyles.AllowInnerWhite | DateTimeStyles.AllowLeadingWhite | DateTimeStyles.AllowTrailingWhite | DateTimeStyles.AllowWhiteSpaces, out var v2) => v2, "TimeSpan" when TimeSpan.TryParse(text, CultureInfo.InvariantCulture, out var v2) => v2, "Boolean" => BooleanValues.Contains(text), _ => null }; } private static readonly HashSet<string> BooleanValues = new HashSet<string>(StringComparer.OrdinalIgnoreCase) { "true", "1", "on", "yes", "ja" }; } }