• C#秘密武器之表达式树


    一、表达式树入门

    Lambda表达式树很复杂,从概念上很难理解清楚,一句话,表达式树是一种数据结构!这里我们通过下面的这个例子来理解一下表达式树,你就能看个大概:

    lambda表达式树动态创建方法 

    static void Main(string[] args)
            {
                //i*j+w*x
                ParameterExpression a = Expression.Parameter(typeof(int),"i");   //创建一个表达式树中的参数,作为一个节点,这里是最下层的节点
                ParameterExpression b = Expression.Parameter(typeof(int),"j");
                BinaryExpression r1 = Expression.Multiply(a,b);    //这里i*j,生成表达式树中的一个节点,比上面节点高一级
    
                ParameterExpression c = Expression.Parameter(typeof(int), "w");
                ParameterExpression d = Expression.Parameter(typeof(int), "x");
                BinaryExpression r2 = Expression.Multiply(c, d);
    
                BinaryExpression result = Expression.Add(r1,r2);   //运算两个中级节点,产生终结点
    
                Expression<Func<int, int, int, int, int>> lambda = Expression.Lambda<Func<int, int, int, int, int>>(result,a,b,c,d);
    
                Console.WriteLine(lambda + "");   //输出‘(i,j,w,x)=>((i*j)+(w*x))’,z对应参数b,p对应参数a
    
                Func<int, int, int, int, int> f= lambda.Compile();  //将表达式树描述的lambda表达式,编译为可执行代码,并生成该lambda表达式的委托;
    
                Console.WriteLine(f(1, 1, 1, 1) + "");  //输出结果2
                Console.ReadKey();
            }

    以上代码构成的Lambda表达式树如下图:

    二、常见的一些表达式树用法

    ConstantExpression :表示具有常量值的表达式

    我们构建一个控制台应用程序

    ConstantExpression _constExp = Expression.Constant("aaa",typeof(string));//一个常量
    //Console.Writeline("aaa");
    MethodCallExpression _methodCallexp=Expression.Call(typeof(Console).GetMethod("WriteLine",new Type[]{typeof(string)}),_constExp);
    Expression<Action> consoleLambdaExp = Expression.Lambda<Action>(_methodCallexp);
    consoleLambdaExp.Compile()();
    Console.ReadLine();

    输出一个常量,看一下结果

    ParameterExpression :表示一个参数表达式

    ParameterExpression _parameExp = Expression.Parameter(typeof(string), "MyParameter");
    MethodCallExpression _methodCallexpP = Expression.Call(typeof(Console).GetMethod("WriteLine", new Type[] { typeof(string) }), _parameExp);
    Expression<Action<string>> _consStringExp = Expression.Lambda<Action<string>>(_methodCallexpP, _parameExp);
    _consStringExp.Compile()("Hello!!");

    输出结果:

    MethodCallExpression调用静态方法

    我们建一个返回string的静态方法,传入一个object类型的值

    public static string ConsStr(object str)
    {
        string _str = str + "aa";
        Console.WriteLine(_str);
        return _str;
    }
    ParameterExpression _paraObj = Expression.Parameter(typeof(object), "objPara");
    MethodCallExpression _MyStateMethod = Expression.Call(typeof(Program).GetMethod("ConsStr", new Type[] { typeof(object) }), _paraObj);
    Expression<Func<object, string>> _meyLambdaState = Expression.Lambda<Func<object, string>>(_MyStateMethod, _paraObj);
    string s_tr = _meyLambdaState.Compile()("ni Hao");
    Console.WriteLine("返回值: " + s_tr);

    输出结果:

     

    MethodCallExpression调用实例方法

    我们写一个非静态方法

    public string ConsStr2(object str)
    {
        string _str = str + "aa";
        Console.WriteLine(_str);
        return _str;
    }

    Expression.Call为我们提供了我们想要的重载:

    Program _pg = new Program();
    ParameterExpression _paraObj2 = Expression.Parameter(typeof(object), "objPara");
    MethodCallExpression _MyStateMethod2 = Expression.Call(Expression.Constant(_pg), typeof(Program).GetMethod("ConsStr2"), _paraObj2);
    Expression<Func<object, string>> _meyLambdaState2 = Expression.Lambda<Func<object, string>>(_MyStateMethod2, _paraObj2);
    string s_tr2 = _meyLambdaState.Compile()("you shi ni ");
    Console.WriteLine("返回值: " + s_tr2);

    输出结果:

    UnaryExpression:一元运算符表达式

    用UnaryExpression做一个5--的表达式:

    ConstantExpression _consNum = Expression.Constant(5, typeof(int));
    UnaryExpression _unaryPlus = Expression.Decrement(_consNum);
    Expression<Func<int>> _unaryLam = Expression.Lambda<Func<int>>(_unaryPlus);
    Console.WriteLine(_unaryLam.Compile()());

    输出结果:

    BinaryExpression : 二元运算符表达式

    BinaryExpression  我们做一个a+b的例子

    ParameterExpression _ParaA = Expression.Parameter(typeof(int), "a");
    ParameterExpression _ParaB = Expression.Parameter(typeof(int), "b");
    BinaryExpression _BinaAdd = Expression.Add(_ParaA, _ParaB);
    Expression<Func<int, int, int>> _MyBinaryAddLamb = Expression.Lambda<Func<int, int, int>>(_BinaAdd, new ParameterExpression[] { _ParaA, _ParaB });
    Console.WriteLine("表达式:  "+ _MyBinaryAddLamb);
    Console.WriteLine(_MyBinaryAddLamb.Compile()(3, 6));

    输出结果:

    两个表达式也可以放在一起:(a+b)*(--c)

    ParameterExpression _ParaA = Expression.Parameter(typeof(int), "a");
    ParameterExpression _ParaB = Expression.Parameter(typeof(int), "b");
    BinaryExpression _BinaAdd = Expression.Add(_ParaA, _ParaB);  //a+b
    ParameterExpression _paraC = Expression.Parameter(typeof(int), "c");
    UnaryExpression _paraDecr = Expression.Decrement(_paraC);    //(a+b)*(--c)
    BinaryExpression _binaMultiply = Expression.Multiply(_BinaAdd, _paraDecr);
    Expression<Func<int, int, int, int>> _MyBinaryLamb = Expression.Lambda<Func<int, int, int, int>>(_binaMultiply, new ParameterExpression[] { _ParaA, _ParaB, _paraC });
    Console.WriteLine("表达式:  "+ _MyBinaryLamb);
    Console.WriteLine(_MyBinaryLamb.Compile()(3, 6, 5));

    输出结果:

    三、使用表达式树访问属性

    表达式树可以替换反射,但是未必性能就好,要实际测试一下,另外注意Compile调用过程涉及动态代码生成,所以出于性能考虑最好缓存一下生成的表达式树

    接下来用Expression Tree的方式完成属性赋值和取值的操作,它们实现在如下两个静态方法中:CreateGetPropertyValueFunc和CreateSetPropertyValueAction。下面是CreateGetPropertyValueFunc的定义,它返回的是一个Func<object.object>委托:

     public static Func<object, object> CreateGetPropertyValueFunc()   
     {   
    var property = typeof(IFoo).GetProperty("Bar"); var target = Expression.Parameter(typeof(object)); var castTarget = Expression.Convert(target, typeof(IFoo)); var getPropertyValue = Expression.Property(castTarget, property); var castPropertyvalue = Expression.Convert(getPropertyValue, typeof(object)); return Expression.Lambda<Func<object, object>>(castPropertyvalue , target).Compile(); }

    下面是CreateSetPropertyValueAction方法,返回一个Action<object.object>委托:

     public static Action<object, object> CreateSetPropertyValueAction()   
     {   
         var property            = typeof(IFoo).GetProperty("Bar");   
         var target              = Expression.Parameter(typeof(object));   
         var propertyValue       = Expression.Parameter(typeof(object));   
         var castTarget          = Expression.Convert(target, typeof(IFoo));   
         var castPropertyValue   = Expression.Convert(propertyValue, property.PropertyType);   
         var setPropertyValue    = Expression.Call(castTarget, property.GetSetMethod(), castPropertyValue);   
         return Expression.Lambda<Action<object, object>>(setPropertyValue, target, propertyValue).Compile();  
     }

    注:表达式树的水很深,此处只是入门,以后仍需继续研究使用~

  • 相关阅读:
    python学习笔记之九:模块和包
    python学习笔记之八:迭代器和生成器
    python学习笔记之七:魔法方法,属性
    python学习笔记之六:更加抽象
    python学习笔记之五:抽象
    python学习笔记之四:条件,循环和其他语句
    python学习笔记之三:字典,当索引不好用时
    python学习笔记之二:使用字符串
    yolo自己的数据集中LabelImg的安装出现No module named 'libs.resources'错误
    django2 rest_framework + vue.js + mysql5.6 实现增删改查
  • 原文地址:https://www.cnblogs.com/WeiGe/p/4215752.html
Copyright © 2020-2023  润新知