日期:2014-05-18 浏览次数:21123 次
需求:使用泛型创建有参数的对象(性能上考虑,不使用反射创建)。
使用泛型创建无参(默认)构造函数的对象可以用
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;
}
}
}