C#中关于表达式树的简单介绍


本文摘自PHP中文网,作者黄舟,侵删。

表达式树可以说是Linq的核心之一,为什么是Linq的核心之一呢?因为表达式树使得c#不再是仅仅能编译成IL,我们可以通过c#生成一个表达式树,将结果作为一个中间格式,在将其转换成目标平台上的本机语言。比如SQL。我们常用的Linq to sql就是这样生成SQL的。

表达式树是.NET 3.5之后引入的,它是一个强大灵活的工具(比如用在LINQ中构造动态查询)。

先来看看Expression类的API接口:

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

32

33

34

35

36

37

38

39

40

41

42

43

44

45

46

namespace System.Linq.Expressions

{

    //

    // 摘要:

    //     以表达式目录树的形式将强类型 lambda 表达式表示为数据结构。此类不能被继承。

    //

    // 类型参数:

    //   TDelegate:

    //     System.Linq.Expressions.Expression`1 表示的委托的类型。

    public sealed class Expression<TDelegate> : LambdaExpression

    {

        //

        // 摘要:

        //     将表达式树描述的 lambda 表达式编译为可执行代码,并生成表示该 lambda 表达式的委托。

        //

        // 返回结果:

        //     一个 TDelegate 类型的委托,它表示由 System.Linq.Expressions.Expression`1 描述的已编译的 lambda 表达式。

        public TDelegate Compile();

        //

        // 摘要:

        //     生成表示 lambda 表达式的委托。

        //

        // 参数:

        //   debugInfoGenerator:

        //     编译器用于标记序列点并批注局部变量的调试信息生成器。

        //

        // 返回结果:

        //     包含 lambda 的已编译版本的委托。

        public TDelegate Compile(DebugInfoGenerator debugInfoGenerator);

        //

        // 摘要:

        //     创建一个与此表达式类似的新表达式,但使用所提供的子级。如果所有子级都相同,则将返回此表达式。

        //

        // 参数:

        //   body:

        //     结果的 System.Linq.Expressions.LambdaExpression.Body 属性。

        //

        //   parameters:

        //     结果的 System.Linq.Expressions.LambdaExpression.Parameters 属性。

        //

        // 返回结果:

        //     此表达式(如果未更改任何子级),或带有更新的子级的表达式。

        public Expression<TDelegate> Update(Expression body, IEnumerable<ParameterExpression> parameters);

        protected internal override Expression Accept(ExpressionVisitor visitor);

    }

}

表达式树的语法如下:


1

Expression<Func<type,returnType>> = (param) => lamdaexpresion;

例如:


1

Expression<Func<int, int, int>> expr = (x, y) => x+y;

我们运行以上代码,并在VS调试模似下查看这个表达式树:

可以看到表达式树主要由下面四部分组成:

1、Body 主体部分

2、Parameters 参数部分

3、NodeType 节点类型

4、Lambda表达式类型

在上述代码中,主体即为:x+y,参数为(x,y),NodeType为Lambda表达式,返回值为int

主体部分可以是表达式,但是不能包含语句。例如:我定义一个委托,Lambda表达式可以这样写


1

Func<int, int, int> func = (x, y) => x + y;

也可以这样写:


1

Func<int, int, int> func = (x, y) => { return x + y; };

但是,在表达式树种,只能用第一种写法,如果使用第二种写法编译汇报错误:无法将具有语句体的 lambda 表达式转换为表达式树。

除了上边的写法,表达式树还有可以这么写:

1

2

3

4

5

6

ParameterExpression pex1 = Expression.Parameter(typeof(int), "x");//第一个参数

ParameterExpression pex2 = Expression.Parameter(typeof(int), "y");//第二个参数

 

BinaryExpression bexp = Expression.Add(pex1, pex2);//加法

 

var lambdaExp = Expression.Lambda<Func<int, int, int>>(bexp, new ParameterExpression[] {pex1,pex2 });


VS调试模式下可以看到两种写法生成的表达式树是一样的

将表达式树编译成委托

LambdaExpression是从Expression派生的类型。泛型类Expression<TDelegate>是从LambdaExpression派生的,其中泛型参数TDelegate必须是委托类型。

LambdaExpression有个Compile方法能创建恰当类型的一个委托。而Expression<TDelegate>的Compile方法返回TDelegate类型的委托。来看看下面的例子:

1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

16

Expression<Func<int, int, int>> expr = (x, y) => x + y;

 

ParameterExpression pex1 = Expression.Parameter(typeof(int), "x");//第一个参数

ParameterExpression pex2 = Expression.Parameter(typeof(int), "y");//第二个参数

 

BinaryExpression bexp = Expression.Add(pex1, pex2);//主体,加法

 

//使用Expression.Lambda方法,创建一个委托类型已知的Expression

Expression<Func<int,int,int>> lambdaExp

    = Expression.Lambda<Func<int, int, int>>(bexp, new ParameterExpression[] { pex1, pex2 });

 

Func<int,int,int> tDelegate = lambdaExp.Compile();//编译成委托

 

Console.WriteLine(tDelegate(1, 3));

 

Console.Read();

我们运行上面代码,结果为:4。我们写了一大堆代码,本质上就是用表达式树计算了1+3的结果。

以上就是C#中关于表达式树的简单介绍的详细内容!

相关阅读 >>

return后面的值不能为表达式吗?

.net中core使用socket与树莓派进行通信的实例分析(图文)

c#中foreach实例代码

使用c#操作windowad之添加对象到用户组

windows登录功能使用c#实现的示例

如何使用c#自定义音乐播放器进度条的实例分析

详细介绍.net并行与多线程学习基础

.net是干嘛的和java的区别

c# 一些面试试题的实例教程

.net是什么

更多相关阅读请进入《csharp》频道 >>




打赏

取消

感谢您的支持,我会继续努力的!

扫码支持
扫码打赏,您说多少就多少

打开支付宝扫一扫,即可进行扫码打赏哦

分享从这里开始,精彩与您同在

评论

管理员已关闭评论功能...