Business Logic Toolkit for .NET
www.bltoolkit.net
|  Home   |  Download   |  Documentation   |  Discussions   |  License   |

  Source.Common.ConvertT.cs

 
using System;
using System.Reflection;

namespace BLToolkit.Common
{
    using Reflection;

    /// <summary>
    /// Converts a base data type to another base data type.
    /// </summary>
    /// <typeparam name="P">Source data type.</typeparam>
    /// <typeparam name="T">Destination data type.</typeparam>
    public static class Convert<T,P>
    {
        /// <summary>
        /// Represents a method that converts an object from one type to another type.
        /// </summary>
        /// <param name="p">A value to convert to the target type.</param>
        /// <returns>The <typeparamref name="T"/> that represents the converted <paramref name="p"/>.</returns>
        public delegate T ConvertMethod(P p);

        /// <summary>Converts an array of one type to an array of another type.</summary>
        /// <returns>An array of the target type containing the converted elements from the source array.</returns>
        /// <param name="src">The one-dimensional, zero-based <see cref="T:System.Array"></see> to convert to a target type.</param>
        /// <exception cref="T:System.ArgumentNullException">array is null.-or-converter is null.</exception>
        public static T[] FromArray(P[] src)
        {
            // Note that type parameters are in reverse order.
            //
            return Array.ConvertAll<P,T>(src, (Converter<P,T>)((object)From));
        }

        ///<summary>
        /// Converter instance.
        ///</summary>
        public static ConvertMethod From = GetConverter();

        ///<summary>
        /// Initializes converter instance.
        ///</summary>
        ///<returns>Converter instance.</returns>
        public static ConvertMethod GetConverter()
        {
            Type from = typeof(P);
            Type to   = typeof(T);

            // Convert to the same type.
            //
            if (to == from)
                return (ConvertMethod)(object)(Convert<P,P>.ConvertMethod)SameType;

            if (from.IsEnum)
                from = Enum.GetUnderlyingType(from);

            if (to.IsEnum)
                to = Enum.GetUnderlyingType(to);

            if (TypeHelper.IsSameOrParent(to, from))
                return Assignable;

            string methodName;

            if (TypeHelper.IsNullable(to))
                methodName = "ToNullable" + to.GetGenericArguments()[0].Name;
            else if (to.IsArray)
                methodName = "To" + to.GetElementType().Name + "Array";
            else
                methodName = "To" + to.Name;

            MethodInfo mi = typeof(Convert).GetMethod(methodName,
                BindingFlags.Public | BindingFlags.Static | BindingFlags.ExactBinding,
                null, new Type[] {from}, null) ?? FindTypeCastOperator(to) ?? FindTypeCastOperator(from);

            if (mi == null && TypeHelper.IsNullable(to))
            {
                // To-nullable conversion.
                // We have to use reflection to enforce some constraints.
                //
                Type toType   = to.GetGenericArguments()[0];
                Type fromType = TypeHelper.IsNullable(from)? from.GetGenericArguments()[0]: from;
                methodName = TypeHelper.IsNullable(from) ? "FromNullable" : "From";

                mi = typeof(NullableConvert<,>)
                    .MakeGenericType(toType, fromType)
                    .GetMethod(methodName, BindingFlags.Public | BindingFlags.Static);
            }

            if (mi != null)
                return (ConvertMethod)Delegate.CreateDelegate(typeof(ConvertMethod), mi);

            return Default;
        }

        private static MethodInfo FindTypeCastOperator(Type t)
        {
            foreach (MethodInfo mi in t.GetMethods(BindingFlags.Public | BindingFlags.Static))
            {
                if (mi.IsSpecialName && mi.ReturnType == typeof(T) && (mi.Name == "op_Implicit" || mi.Name == "op_Explicit"))
                {
                    ParameterInfo[] parameters = mi.GetParameters();

                    if (1 == parameters.Length && parameters[0].ParameterType == typeof(P))
                        return mi;
                }
            }

            return null;
        }

        private static P SameType  (P p) { return p; }
        private static T Assignable(P p) { return (T)(object)p; }
        private static T Default   (P p) { return (T)System.Convert.ChangeType(p, typeof(T)); }
    }

    /// <summary>
    /// Converts a base data type to another base data type.
    /// </summary>
    /// <typeparam name="T">Destination data type.</typeparam>
    public static class ConvertTo<T>
    {
        /// <summary>Returns an <typeparamref name="T"/> whose value is equivalent to the specified value.</summary>
        /// <returns>The <typeparamref name="T"/> that represents the converted <paramref name="p"/>.</returns>
        /// <param name="p">A value to convert to the target type.</param>
        public static T From<P>(P p)
        {
            return Convert<T,P>.From(p);
        }
    }

    internal static class NullableConvert<T,P>
        where T: struct
        where P: struct
    {
        public static T? FromNullable(P? p)
        {
            return p.HasValue? From(p.Value): null;
        }

        public static T? From(P p)
        {
            return Convert<T,P>.From(p);
        }
    }
}
 
© 2010 www.bltoolkit.net
support@bltoolkit.net