Mercurial > pub > bltoolkit
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); } } + } +}