浅谈表达式树和泛型委托

开发
本文将讨论.NET中的表达式树和泛型委托。表达式树又称为表达式目录树,以数据形式表示语言级代码。

什么是表达式树?

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

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

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

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

MethodCallExpressionorderByCallExpression=Expression.Call(
typeof(Queryable),
"OrderBy",
newType[]{queryableData.ElementType,queryableData.ElementType},
whereCallExpression,
Expression.Lambda>(pe,newParameterExpression[]{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委托
///

///para1
///para2
///
publicdelegatedoublePowerCompute(doublenum_1,doublenum_2);

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

///
///(a+b)^b方法
///

///para1
///para2
///
publicstaticdoubleGetPowerCompute(doublenum_1,doublenum_2)
{
returnMath.Pow((num_1+num_2),num_2);
}
 3):调用:
doubledResult=0;
PowerComputepc=GetPowerCompute;
dResult=pc(2,2);
Console.WriteLine(dResult.ToString());

2:泛型委托实现:

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

2):调用

Funcfc=GetPowerCompute;
dResult=fc(2,2);
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的表达式树生成可执行代码并且在客户端进行调用的代码:

ParameterExpressionpenum_1=Expression.Parameter(typeof(double),"num_1");
ParameterExpressionpenum_2=Expression.Parameter(typeof(double),"num_2");
BinaryExpression_be=Expression.Add(penum_1,penum_2);
BinaryExpression_be2=Expression.Power(_be,penum_2);
Expression>ef=
Expression.Lambda>(_be2,newParameterExpression[]{

penum_1,penum_2});
Funccf=ef.Compile();
returncf(num_1,num_2);

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


表达式树的修改:

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

【编辑推荐】

  1. 换一个角度看.NET中的理解委托和事件
  2. 跟MVP学C#视频教程之九 委托与事件
  3. .NET反射、委托技术与设计模式
责任编辑:彭凡 来源: cnblogs
相关推荐

2009-08-27 09:57:50

C# Lambda表达

2011-05-20 17:50:45

C#

2009-09-09 13:01:33

LINQ Lambda

2010-09-14 14:05:42

C#委托

2009-08-10 09:41:07

.NET Lambda

2019-07-17 15:45:47

正则表达式字符串前端

2009-09-17 09:15:49

Linq表达式树

2009-04-29 09:05:59

Lambda抽象代表.NET

2018-09-27 15:25:08

正则表达式前端

2014-01-05 17:41:09

PostgreSQL表达式

2009-02-17 09:10:01

正则表达式Java优化

2009-09-14 14:01:21

LINQ泛型数据集

2009-08-24 15:50:23

C# 泛型C# 泛型委托

2009-07-21 14:38:08

Scalamatch表达式break和conti

2010-11-16 14:53:02

Oracle游标表达式

2009-09-17 09:09:50

Lambda表达式Linq查询

2009-09-16 10:48:31

PHP正则表达式

2009-06-24 10:25:25

C#泛型

2009-08-24 14:43:35

C# 泛型

2023-11-02 18:45:00

Rust编程表达式
点赞
收藏

51CTO技术栈公众号