使用表达式树创建对象
使用表达式树创建对象
转载:使用表达式树创建对象 - 不夜橙 - 博客园 (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#反射加速属性和方法的调用