使用表达式树创建对象
转载:使用表达式树创建对象 - 不夜橙 - 博客园 (cnblogs.com)
原来程序中的代码:
1 2 3 4 |
public static T GetInstance<T>() where T : new ()
{
return new T();
}
|
需要扩展这个方法支持参数传递。可惜泛型约束不支持指定构造函数参数,那只好使用对象反射了。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 |
public class A
{
public A( string A)
{
}
public string P1 { get ; set ; }
}
//反射创建对象A
Activator.CreateInstance(t, "sss" );
|
这样的话对象创建速度一下会变得很慢吧。正好想到 ExpressionTree,使用Expression.New并且缓存Expression方式应该可以提高些速度。正好找到了相关用法 http://geekswithblogs.net/mrsteve/archive/2012/01/11/csharp-expression-trees-create-instance-from-type-extension-method.aspx ,核心代码如下
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 |
public static Func< string , T> GetExpression<T>()
{
var argumentType = new [] { typeof ( string ) };
// Get the Constructor which matches the given argument Types:
var constructor = typeof (T).GetConstructor(
BindingFlags.Instance | BindingFlags.Public,
null ,
CallingConventions.HasThis,
argumentType,
new ParameterModifier[0]);
// Get a set of Expressions representing the parameters which will be passed to the Func:
var lamdaParameterExpressions = GetLambdaParameterExpressions(argumentType).ToArray();
// Get a set of Expressions representing the parameters which will be passed to the constructor:
var constructorParameterExpressions = GetConstructorParameterExpressions(
lamdaParameterExpressions,
argumentType).ToArray();
// Get an Expression representing the constructor call, passing in the constructor parameters:
var constructorCallExpression = Expression.New(constructor, constructorParameterExpressions);
// Compile the Expression into a Func which takes three arguments and returns the constructed object:
var constructorCallingLambda = Expression
.Lambda<Func< string , T>>(constructorCallExpression, lamdaParameterExpressions)
.Compile();
return constructorCallingLambda;
}
private static IEnumerable<ParameterExpression> GetLambdaParameterExpressions(Type[] argumentTypes)
{
for ( int i = 0; i < argumentTypes.Length; i++)
{
yield return Expression.Parameter( typeof ( object ), string .Concat( "param" , i));
}
}
private static IEnumerable<UnaryExpression> GetConstructorParameterExpressions(
ParameterExpression[] lamdaParameterExpressions,
Type[] constructorArgumentTypes)
{
for ( int i = 0; i < constructorArgumentTypes.Length; i++)
{
// Each parameter passed to the lambda is of type object, so we need to convert it into
// the appropriate type for the constructor:
yield return Expression.Convert(lamdaParameterExpressions[i], constructorArgumentTypes[i]);
}
}
|
试试有何提升:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 |
static void Main( string [] args)
{
var t = typeof (A);
var count = 10000000;
var expression = GetExpression<A>();
var ts2 = Timer.Time(() =>
{
var o = expression.Invoke( "sss" );
}, count);
var ts= Timer.Time(() =>
{
var o = Activator.CreateInstance(t, "sss" );
}, count);
var ts3 = Timer.Time(() =>
{
var o = new A( "SSS" );
}, count);
Console.WriteLine( "{0}:{1} " , "Direct" , ts3.Milliseconds);
Console.WriteLine( "{0}:{1}" , "Activator.CreateInstance" , ts.Milliseconds);
Console.WriteLine( "{0}:{1}" , "Expression" , ts2.Milliseconds);
Console.ReadLine();
}
|
结果:
结论
使用Expression代替Activator.CreateInstance加快对象创建速度。另外使用Expression&Delegate.CreateDelegate代替传统C#反射加速属性和方法的调用