• 使用表达式树创建对象


    原来程序中的代码:

    public static T GetInstance<T>() where T : new()
            {
                return new T();
            }

    需要扩展这个方法支持参数传递。可惜泛型约束不支持指定构造函数参数,那只好使用对象反射了。

     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 ,核心代码如下

      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]);
                }
            }

    试试有何提升:

    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#反射加速属性和方法的调用

    参考:

    http://geekswithblogs.net/mrsteve/archive/2012/01/11/csharp-expression-trees-create-instance-from-type-extension-method.aspx

    http://www.cnblogs.com/artech/archive/2011/03/26/Propertyaccesstest.html

  • 相关阅读:
    git的使用
    对大学学习的一些看法
    远程连接mysql失败情况总结
    缓存穿透、缓存击穿、缓存雪崩
    Hello Redis
    Celery的简单使用
    git操作
    码云、github同时配置ssh key,解决冲突问题
    阿里云短信验证码服务
    Vue中img标签的src属性绑定的坑
  • 原文地址:https://www.cnblogs.com/miku/p/4456867.html
Copyright © 2020-2023  润新知