diff Source/Common/ConvertT.cs @ 0:f990fcb411a9

Копия текущей версии из github
author cin
date Thu, 27 Mar 2014 21:46:09 +0400
parents
children
line wrap: on
line diff
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/Source/Common/ConvertT.cs	Thu Mar 27 21:46:09 2014 +0400
@@ -0,0 +1,151 @@
+using System;
+using System.Reflection;
+using System.Threading;
+
+namespace BLToolkit.Common
+{
+	using Reflection;
+
+	/// <summary>
+	/// Converts a base data type to another base data type.
+	/// </summary>
+	/// <typeparam name="T">Destination data type.</typeparam>
+	/// <typeparam name="P">Source 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)
+		{
+			var arr = new T[src.Length];
+
+			for (var i = 0; i < arr.Length; i++)
+				arr[i] = From(src[i]);
+
+			return arr;
+		}
+
+		///<summary>
+		/// Converter instance.
+		///</summary>
+		public static ConvertMethod From = GetConverter();
+
+		///<summary>
+		/// Initializes converter instance.
+		///</summary>
+		///<returns>Converter instance.</returns>
+		public static ConvertMethod GetConverter()
+		{
+			var from = typeof(P);
+			var 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 if (to.Name == "Binary")
+				methodName = "ToLinq" + to.Name;
+			else
+				methodName = "To" + to.Name;
+
+			var mi = typeof(Convert).GetMethod(methodName,
+				BindingFlags.Public | BindingFlags.Static | BindingFlags.ExactBinding,
+				null, new[] { from }, null) ?? FindTypeCastOperator(to) ?? FindTypeCastOperator(from);
+
+			if (mi == null && TypeHelper.IsNullable(to))
+			{
+				// To-nullable conversion.
+				// We have to use reflection to enforce some constraints.
+				//
+				var toType   = to.GetGenericArguments()[0];
+				var 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 (var mi in t.GetMethods(BindingFlags.Public | BindingFlags.Static))
+			{
+				if (mi.IsSpecialName && mi.ReturnType == typeof(T) && (mi.Name == "op_Implicit" || mi.Name == "op_Explicit"))
+				{
+					var 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), Thread.CurrentThread.CurrentCulture); }
+	}
+
+	/// <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);
+		}
+	}
+}