使用表达式树创建对象

使用表达式树创建对象

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

上一篇:mongo-express 远程代码执行漏洞分析


下一篇:用于 ‘Suse‘ Linux 包管理的 Zypper 命令大全