diff Source/Reflection/ExprTypeAccessor.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/Reflection/ExprTypeAccessor.cs	Thu Mar 27 21:46:09 2014 +0400
@@ -0,0 +1,125 @@
+using System;
+using System.Linq;
+using System.Collections.Generic;
+using System.Linq.Expressions;
+using System.Reflection;
+
+namespace BLToolkit.Reflection
+{
+	using TypeBuilder;
+
+	class ExprTypeAccessor<T,TOriginal> : TypeAccessor
+	{
+		static ExprTypeAccessor()
+		{
+			// Create Instance.
+			//
+			var type     = typeof(T);
+			var typeInit = typeof(InitContext);
+			var initPar  = Expression.Parameter(typeInit, "ctx");
+
+			if (type.IsValueType)
+			{
+				_createInstance = () => default(T);
+				_createInstanceInit = ctx => default(T);
+			}
+			else
+			{
+				var ctor = type.GetConstructor(BindingFlags.Instance | BindingFlags.NonPublic | BindingFlags.Public, null, Type.EmptyTypes, null);
+				var ctorInit = type.GetConstructor(BindingFlags.Instance | BindingFlags.NonPublic | BindingFlags.Public, null, new[] { typeInit }, null);
+
+				if (ctor == null && ctorInit == null)
+				{
+					Expression<Func<T>> mi = () => ThrowException();
+
+					var body = Expression.Call(null, ((MethodCallExpression)mi.Body).Method);
+
+					_createInstance = Expression.Lambda<Func<T>>(body).Compile();
+					_createInstanceInit = Expression.Lambda<Func<InitContext, T>>(body, initPar).Compile();
+				}
+				else
+				{
+					_createInstance = ctor != null ?
+						Expression.Lambda<Func<T>>(Expression.New(ctor)).Compile() :
+						Expression.Lambda<Func<T>>(Expression.New(ctorInit, Expression.Constant(null))).Compile();
+
+					_createInstanceInit = ctorInit != null ?
+						Expression.Lambda<Func<InitContext, T>>(Expression.New(ctorInit, initPar), initPar).Compile() :
+						Expression.Lambda<Func<InitContext, T>>(Expression.New(ctor), initPar).Compile();
+				}
+			}
+
+			var originalType = typeof(TOriginal);
+
+			// Add fields.
+			//
+			foreach (var fi in originalType.GetFields(BindingFlags.Instance | BindingFlags.Public))
+				_members.Add(fi);
+
+			foreach (var pi in originalType.GetProperties(BindingFlags.Instance | BindingFlags.Public))
+				if (pi.GetIndexParameters().Length == 0)
+					_members.Add(pi);
+
+			// Add explicit iterface implementation properties support
+			// Or maybe we should support all private fields/properties?
+			var interfaceMethods = originalType.GetInterfaces().SelectMany(ti => originalType.GetInterfaceMap(ti).TargetMethods).ToList();
+
+			if (interfaceMethods.Count > 0)
+			{
+				foreach (var pi in originalType.GetProperties(BindingFlags.Instance | BindingFlags.NonPublic))
+				{
+					if (pi.GetIndexParameters().Length == 0)
+					{
+						var getMethod = pi.GetGetMethod(true);
+						var setMethod = pi.GetSetMethod(true);
+
+						if ((getMethod == null || interfaceMethods.Contains(getMethod)) &&
+							(setMethod == null || interfaceMethods.Contains(setMethod)))
+						{
+							_members.Add(pi);
+						}
+					}
+				}
+			}
+
+			// ObjectFactory
+			//
+			var attr = TypeHelper.GetFirstAttribute(type, typeof(ObjectFactoryAttribute));
+
+			if (attr != null)
+				_objectFactory = ((ObjectFactoryAttribute)attr).ObjectFactory;
+		}
+
+		static T ThrowException()
+		{
+			throw new TypeBuilderException(string.Format("The '{0}' type must have default or init constructor.", typeof(TOriginal).FullName));
+		}
+
+		static readonly List<MemberInfo> _members = new List<MemberInfo>();
+		static readonly IObjectFactory   _objectFactory;
+
+		public ExprTypeAccessor()
+		{
+			foreach (var member in _members)
+				AddMember(ExprMemberAccessor.GetMemberAccessor(this, member.Name));
+
+			ObjectFactory = _objectFactory;
+		}
+
+		static readonly Func<T> _createInstance;
+		public override object   CreateInstance()
+		{
+			return _createInstance();
+		}
+
+		static readonly Func<InitContext,T> _createInstanceInit;
+
+		public override object CreateInstance(InitContext context)
+		{
+			return _createInstanceInit(context);
+		}
+
+		public override Type Type         { get { return typeof(T);         } }
+		public override Type OriginalType { get { return typeof(TOriginal); } }
+	}
+}