使用表达式树创建对象

使用表达式树创建对象

转载:使用表达式树创建对象 - 不夜橙 - 博客园 (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();
        }

结果:

image

 

结论

使用Expression代替Activator.CreateInstance加快对象创建速度。另外使用Expression&Delegate.CreateDelegate代替传统C#反射加速属性和方法的调用

posted @ 2021-09-15 16:53  vba是最好的语言  阅读(84)  评论(0编辑  收藏  举报