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

  Source.Reflection.ExprTypeAccessor.cs

 
using System;
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)
            {
                var body = Expression.Constant(default(T));

                _createInstance = Expression.Lambda<Func<T>>(body).Compile();
                _createInstanceInit = Expression.Lambda<Func<InitContext, T>>(body, initPar).Compile();
            }
            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();
                }
            }

            // Add fields.
            //
            foreach (var fi in typeof(TOriginal).GetFields(BindingFlags.Instance | BindingFlags.Public))
                _members.Add(fi);

            foreach (var pi in typeof(TOriginal).GetProperties(BindingFlags.Instance | BindingFlags.Public))
                if (pi.GetIndexParameters().Length == 0)
                    _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); } }
    }
}
 
© 2010 www.bltoolkit.net
support@bltoolkit.net