zoukankan      html  css  js  c++  java
  • 艾伟:表达式树和泛型委托 狼人:

    什么是表达式树?

      表达式树又称为表达式目录树,以数据形式表示语言级代码。所有的数据都存储在树结构中,每个结点表示一个表达式(Expression)。要想手动生成表达式树我们需要引用System.Linq.Expressions 命名空间,最重要的一个类是Expression,它是所有表达式的基类。例如:

      1:参数表达式:ParameterExpression,就是一个方法中的参数,例如 search(string key),key可以看成是一个参数表达式。

      2:二元表达式:BinaryExpression,例如a+b等。

      3:方法调用表达式:MethodCallExpression,例如:自定义LINQ提供程序中实现orderby 的操作:

    MethodCallExpression orderByCallExpression = Expression.Call(
                    
    typeof(Queryable),
                    
    "OrderBy",
                    
    new Type[] { queryableData.ElementType, queryableData.ElementType
     },
                    whereCallExpression,
                    Expression.Lambda
    <Func<stringstring>>(pe, new ParameterExpression
    [] { pe }));

      4:常数表达式:ConstantExpression,例如数值5。

      5:字段或属性表达式:MemberExpression,例如str.Length。Expression.Property(pe,   typeof(string).GetProperty("Length"));

      6:带有条件运算的表达式:ConditionalExpression。

      7:描述lambda表达式:LambdaExpression

      8:一元运算符的表达式:UnaryExpression

      9:表达式和类型之间的相关操作:TypeBinaryExpression等等,它们都继承Expression。

    泛型委托:

      表达式树经常与泛型委托一起使用,这里简单介绍下什么是泛型委托。Func<(Of <(T, TResult>)>) 泛型委托:封装一个具有一个参数并返回 TResult 参数指定的类型值的方法。如果想增加参数可以写成Func<(Of <(T1,T2, TResult>)>) 等。这种方法比起传统的显示声明委托的方法从代码结构上要简化不少,我们不用特意去申请一个delegate,所有的委托都可以用泛型委托来代替。这里简单来实现一个算术表达式来说明泛型委托的好处。

      算术表达:(a+b)^b

      1:传统的显示申明委托方式。

      1):申明一个委托:

    /// 
        
    /// (a+b)^b 委托
        
    /// 
        
    /// para 1
        
    /// para 2
        
    /// 
        public delegate double PowerCompute(double num_1, double num_2);

      2):编码委托对应的方法体

    /// 
            
    /// (a+b)^b方法
            
    /// 
            
    /// para 1
            
    /// para 2
            
    /// 
            public static  double GetPowerCompute(double num_1, double num_2)
            {
                
    return Math.Pow((num_1 + num_2), num_2);
            }

      3):调用:

    double dResult = 0;
                PowerCompute pc 
    = GetPowerCompute;
                dResult 
    = pc(22);
                Console.WriteLine(dResult.ToString());

      2:泛型委托实现:

      1):编码委托对应的方法体,方法同上面代码中第二步。

      2):调用

    Func<double ,double ,double > fc=GetPowerCompute;
                dResult 
    = fc(22);
                Console.WriteLine(dResult.ToString());

      表达式树的执行:

      表达式树和泛型委托:   这里实现一个简单的表达式树,实现(a+b)^b, 过程中需要知道以下三个比较重要的方法。

      1:Expression<(Of <(TDelegate>)>) :以表达式目录树的形式将强类型 lambda 表达式表示为数据结构。

      2: Expression.Lambda方法:创建一个表示 lambda 表达式的表达式目录树。

      3:Expression<(Of <(TDelegate>)>).Compile :将表达式目录树描述的 lambda 表达式编译为可执行代码。

      下面是(a+b)^b的表达式树生成可执行代码并且在客户端进行调用的代码:

    ParameterExpression penum_1 = Expression.Parameter(typeof(double), "num_1");
                ParameterExpression penum_2 
    = Expression.Parameter(typeof(double),
    "num_2");
                BinaryExpression _be 
    = Expression.Add(penum_1, penum_2);
                BinaryExpression _be2 
    = Expression.Power(_be, penum_2);
                Expression
    <Func<doubledoubledouble>> ef = Expression.Lambda<Func
    <
    doubledoubledouble>>(_be2, new ParameterExpression[] { 

    penum_1, penum_2 });
                Func
    <doubledoubledouble> cf = ef.Compile();
                
    return cf(num_1 ,num_2 );

    下面是(a+b)^b的表达式树的关系图

    表达式树的修改:

      表达式目录树是不可变的,这意味着不能直接修改表达式目录树。若要更改表达式目录树,必须创建现有表达式目录树的一个副本,并在创建副本的过程中执行所需更改。您可以使用表达式目录树访问器遍历现有表达式目录树,并复制它访问的每个节点。我们可以创建自定义类来继承ExpressionVisitor,在自定义类中重定相应方式来达到修改表达式树的目的。 

  • 相关阅读:
    WSL下的Ubuntu 18.04LTS配置软件源和系统更新
    宝塔 5.9.2 最终版 专业版
    宝塔面板7.2.0学习版集合--包含(专业版、企业版及部分插件)
    网络安全学习和CTF必不可少的一些网站
    Hello Blog !
    如何解决机器学习树集成模型的解释性问题
    机器学习建模老司机的几点思考与总结
    2019 秋招提前批蘑菇街一面面经(带答案)
    Java 最全异常讲解
    Spring Context 你真的懂了吗
  • 原文地址:https://www.cnblogs.com/waw/p/2156795.html
Copyright © 2011-2022 走看看