Skip to main content

Extension methods for the Convert class.

using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Globalization;

namespace Extensions
{
    /// <summary>
    /// Type conversion helper
    /// </summary>
    internal static class ConvertExtensions
    {
        private static readonly HashSet<string> _booleanValues = new HashSet<string>(StringComparer.OrdinalIgnoreCase) { "true", "1", "on", "yes", "y" };

        /// <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 self.</param>
        /// <returns>The converted object, or the supplied default self.</returns>
        public static T Convert<T>(this object o, T defaultValue = default(T))
        {
            if (o == null)
            {
                return defaultValue;
            }

            o = o.Convert(typeof(T), defaultValue);

            return o is T ? (T)o : 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>The converted object, or the supplied default value.</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
            {
                object result;
                var s = o as string;

                if (s != null)
                {
                    if (s.Length == 0)
                    {
                        return defaultValue;
                    }
                    result = Parse(type, s);
                    if (result != null)
                    {
                        return result;
                    }
                }

                Type valueType = o.GetType();
                TypeConverter tc = TypeDescriptor.GetConverter(valueType);

                if (tc.CanConvertTo(type))
                {
                    result = tc.ConvertTo(o, type);
                    return result;
                }

                tc = TypeDescriptor.GetConverter(type);

                if (tc.CanConvertFrom(valueType))
                {
                    result = tc.ConvertFrom(o);
                    return result;
                }

                result = Parse(type, o) ?? defaultValue;
                return result;
            }
            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 successfull; otherwise, null.
        /// </returns>
        private static object Parse(Type type, object o)
        {
            if (o == null)
            {
                return null;
            }
            string text = o.ToString();
            if (string.IsNullOrEmpty(text))
            {
                return null;
            }

            object result = null;

            switch (type.Name)
            {
                case "UInt16":
                    {
                        UInt16 v2;
                        if (UInt16.TryParse(text, NumberStyles.Any, CultureInfo.InvariantCulture, out v2))
                        {
                            result = v2;
                        }
                        break;
                    }
                case "UInt32":
                    {
                        UInt32 v2;
                        if (UInt32.TryParse(text, NumberStyles.Any, CultureInfo.InvariantCulture, out v2))
                        {
                            result = v2;
                        }
                        break;
                    }
                case "UInt64":
                    {
                        UInt64 v2;
                        if (UInt64.TryParse(text, NumberStyles.Any, CultureInfo.InvariantCulture, out v2))
                        {
                            result = v2;
                        }
                        break;
                    }
                case "Int16":
                    {
                        Int16 v2;
                        if (Int16.TryParse(text, NumberStyles.Any, CultureInfo.InvariantCulture, out v2))
                        {
                            result = v2;
                        }
                        break;
                    }
                case "Int32":
                    {
                        Int32 v2;
                        if (Int32.TryParse(text, NumberStyles.Any, CultureInfo.InvariantCulture, out v2))
                        {
                            result = v2;
                        }
                        break;
                    }
                case "Int64":
                    {
                        Int64 v2;
                        if (Int64.TryParse(text, NumberStyles.Any, CultureInfo.InvariantCulture, out v2))
                        {
                            result = v2;
                        }
                        break;
                    }
                case "Byte":
                    {
                        Byte v2;
                        if (Byte.TryParse(text, NumberStyles.Any, CultureInfo.InvariantCulture, out v2))
                        {
                            result = v2;
                        }
                        break;
                    }
                case "Boolean":
                    {
                        result = _booleanValues.Contains(text);
                        break;
                    }
                case "Decimal":
                    {
                        decimal v2;
                        if (decimal.TryParse(text, NumberStyles.Any, CultureInfo.InvariantCulture, out v2))
                        {
                            result = v2;
                        }
                        break;
                    }
                case "DateTime":
                    {
                        DateTime v2;
                        if (DateTime.TryParse(text, CultureInfo.InvariantCulture,
                            DateTimeStyles.AllowInnerWhite | DateTimeStyles.AllowLeadingWhite | DateTimeStyles.AllowTrailingWhite | DateTimeStyles.AllowWhiteSpaces,
                            out v2))
                        {
                            result = v2;
                        }
                        break;
                    }
                case "DateTimeOffset":
                    {
                        DateTimeOffset v2;
                        if (DateTimeOffset.TryParse(text, CultureInfo.InvariantCulture,
                            DateTimeStyles.AllowInnerWhite | DateTimeStyles.AllowLeadingWhite | DateTimeStyles.AllowTrailingWhite | DateTimeStyles.AllowWhiteSpaces,
                            out v2))
                        {
                            result = v2;
                        }
                        break;
                    }
                case "TimeSpan":
                    {
                        TimeSpan v2;
                        if (TimeSpan.TryParse(text, CultureInfo.InvariantCulture, out v2))
                        {
                            result = v2;
                        }
                        break;
                    }
            }

            return result;
        }
    }
}