随笔 - 289  文章 - 1  评论 - 2716  阅读 - 195万

表达式树和泛型委托

      什么是表达式树?

          表达式树又称为表达式目录树,以数据形式表示语言级代码。所有的数据都存储在树结构中,每个结点表示一个表达式(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):申明一个委托:

复制代码
/// <summary>
    
/// (a+b)^b 委托
    
/// </summary>
    
/// <param name="num_1">para 1</param>
    
/// <param name="num_2">para 2</param>
    
/// <returns></returns>
    public delegate double PowerCompute(double num_1, double num_2);
复制代码

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

复制代码
/// <summary>
        
/// (a+b)^b方法
        
/// </summary>
        
/// <param name="num_1">para 1</param>
        
/// <param name="num_2">para 2</param>
        
/// <returns></returns>
        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,在自定义类中重定相应方式来达到修改表达式树的目的。 

posted on   min.jiang  阅读(3687)  评论(7编辑  收藏  举报
编辑推荐:
· 从 HTTP 原因短语缺失研究 HTTP/2 和 HTTP/3 的设计差异
· AI与.NET技术实操系列:向量存储与相似性搜索在 .NET 中的实现
· 基于Microsoft.Extensions.AI核心库实现RAG应用
· Linux系列:如何用heaptrack跟踪.NET程序的非托管内存泄露
· 开发者必知的日志记录最佳实践
阅读排行:
· winform 绘制太阳,地球,月球 运作规律
· AI与.NET技术实操系列(五):向量存储与相似性搜索在 .NET 中的实现
· 超详细:普通电脑也行Windows部署deepseek R1训练数据并当服务器共享给他人
· 【硬核科普】Trae如何「偷看」你的代码?零基础破解AI编程运行原理
· 上周热点回顾(3.3-3.9)
< 2009年5月 >
26 27 28 29 30 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 1 2 3 4 5 6

点击右上角即可分享
微信分享提示