日期:2014-05-18  浏览次数:20946 次

C# 泛型 Generics 创建带参对象(取代反射创建对象 优化性能)

需求:使用泛型创建有参数的对象(性能上考虑,不使用反射创建)。

使用泛型创建无参(默认)构造函数的对象可以用
where :T ,new()
new T();
来实现,但是如果构造函数带有参数怎么办呢?

于是就写了一下一段代码:
这里使用了Expression 和 LambdaExpression,目的是为了生成对应类构造函数的委托 ,所以第一次调用会相对慢一点,随后调用就像直接new一样快,适合多次调用情况。

?

?

?

?

using System;
using System.Linq.Expressions;
using System.Reflection;

namespace XXX
{


    /// <summary>
    /// ObjectCreator class used to create object at runtime.
    /// </summary>
    public class ObjectCreator<T>
    {
        #region Singleton
        private ObjectCreator() { }
        public static ObjectCreator<T> Instance
        {
            get { return Nested.m_instance; }
        }
        private class Nested
        {
            static Nested() { }
            internal static readonly ObjectCreator<T> m_instance = new ObjectCreator<T>();
        }
        #endregion

        private ObjectActivator m_rowCreatedActivator = null;

        /// <summary>
        /// Constructor of delegate
        /// </summary>
        /// <typeparam name="T">Type</typeparam>
        /// <param name="args">arguments of Constructor</param>
        /// <returns>Type</returns>
        private delegate T ObjectActivator(params object[] args);

        public T Create(Type[] types, params object[] args)
        {
            if (null == m_rowCreatedActivator)
            {
                m_rowCreatedActivator = ObjectCreator<T>.Instance.GetActivator(typeof(T).GetConstructor(types));
            }
            return m_rowCreatedActivator(args);
        }

        /// <summary>
        /// Create object type at runtime.
        /// </summary>
        /// <typeparam name="T">Type</typeparam>
        /// <param name="ctor">ConstructorInfo of Type</param>
        /// <returns>Constructor of delegate</returns>
        private ObjectActivator GetActivator(ConstructorInfo ctor)
        {
            ParameterInfo[] paramsInfo = ctor.GetParameters();

            //create a single param of type object[]
            ParameterExpression param = Expression.Parameter(typeof(object[]), "args");

            Expression[] argsExp = new Expression[paramsInfo.Length];

            //pick each arg from the params array 
            //and create a typed expression of them
            for (int i = 0; i < paramsInfo.Length; i++)
            {
                Expression index = Expression.Constant(i);
                Type paramType = paramsInfo[i].ParameterType;

                Expression paramAccessorExp = Expression.ArrayIndex(param, index);

                Expression paramCastExp = Expression.Convert(paramAccessorExp, paramType);

                argsExp[i] = paramCastExp;
            }

            //make a NewExpression that calls the
            //ctor with the args we just created
            NewExpression newExp = Expression.New(ctor, argsExp);

            //create a lambda with the New
            //Expression as body and our param object[] as arg
            LambdaExpression lambda = Expression.Lambda(typeof(ObjectActivator), newExp, param);

            //compile it
            ObjectActivator compiled = (ObjectActivator)lambda.Compile();
            return compiled;
        }
    }
}