C# 表达式树讲解(一)

1、前言

一直想写一篇Dpper的定制化扩展的文章,可是里面会设计到对Lambda表达式的解析,而解析Lambda表达式,就必需要知道表达式树的相关知识点。我但愿能经过对各个模块的知识点或者运用可以多一点的讲解,可以帮助到园友了解得更多。虽然讲解得不全面,若是能成为打开这块的一把钥匙,也是蜗牛比较欣慰的。html

表达式系列目录express

C# 表达式树讲解(一)api

C# 表达式树遍历(二)数据结构

C# 表达式树分页扩展(三)ide

C# 表达式树Lambda扩展(四)函数

2、表达树理解

表达式树以树形数据结构表示代码,其中每个节点都是一种表达式,它将咱们原来能够直接由代码编写的逻辑以表达式的方式存储在树状的结构里,从而能够在运行时去解析这个树,而后执行,实现动态的编辑和执行代码。在.Net 里面的Linq to SQL就是对表达式树的解析。spa

这里先讲解下表达式和表达式树,表达式相信你们都知道,好比x+5或者5,均可以算是表达式,而表达式树里面的树指的二叉树,也就是表达式的集合,C#中的Expression类就是表达式类。对于一棵表达式树,其叶子节点都是参数或者常数,非叶子节点都是运算符或者控制符。设计

2.一、表达式的建立

Lambda表达式方法:3d

Expression<Func<int, int,bool>> fun = (x, y) => x < y

这种方法建立出的表达式根节点类型为ExpressionType.Lambda,Type类型为返回值类型typeof(bool)code

组装法(经过 API 建立表达式树):

ParameterExpression numParam = Expression.Parameter(typeof(int), "num");
ConstantExpression five = Expression.Constant(5, typeof(int));
BinaryExpression numLessThanFive = Expression.LessThan(numParam, five);
Expression<Func<int, bool>> lambda1 =
    Expression.Lambda<Func<int, bool>>(
        numLessThanFive,
        new ParameterExpression[] { numParam });

咱们先建立了两个参数表达式num和5,而后用LessThan组装在一块儿,最终的表达式为“num<5”,expr的节点类型为LessThan,Type类型为typeof(bool)

咱们先看看表达式树里面的构造

首先Expression<TDelegate>的功能是将强类型Lambda表达式表示为表达式树形式的数据结构,他的父类是LambdaExpression,比较他们代码可知,Lambda表达式的主体,名称和参数所有保存在LambdaExpression里面。

Expression<TDelegate>与LambdaExpression代码截图:

image

image

LambdaExpression里面的Body就是咱们的表达式。

C#表达式给咱们提供了丰富的表达式类,进入到LambdaExpression类里面

image

方法返回类型以“Expression”结尾的,基本上都是一个表达式类。

每一个表达式表明的定义和建立方法,能够参照微软官方文档https://docs.microsoft.com/zh-cn/dotnet/api/system.linq.expressions.binaryexpression?view=netframework-4.8

下面是日常使用最多的表达式

ConstantExpression:常量表达式

ParameterExpression:参数表达式

UnaryExpression:一元运算符表达式

BinaryExpression:二元运算符表达式

TypeBinaryExpression:is运算符表达式

ConditionalExpression:条件表达式

MemberExpression:访问字段或属性表达式

MethodCallExpression:调用成员函数表达式

Expression<TDelegate>:委托表达式

2.二、表达式的解析

表达式树解析

经过LambdaExpression类咱们能够知道,表达式树包含:参数[Parameters],表达式树类型[NodeType],表达式[Body],返回类型[ReturnType],Lambda表达式的委托[Compile]以及Lambda表达式名称[name],如图所示:

image

表达式解析:

全部的表达式都包含:左节点【Left】,右节点【Right】,类型【NodeType】,不一样的表达式还会有其余属性,这里的左右节点依旧是表达式。

下图是BinaryExpression表达式截图

image

表达式树和表达式里面的类型NodeType是一个枚举,一共有85个类型,有兴趣的朋友能够去了解下。

经常使用的类型以下:

ExpressionType.And:C#中相似于&

ExpressionType.AndAlso:C#中相似于&&

ExpressionType.Or:C#中相似于|

ExpressionType.OrElse:C#中相似于||

ExpressionType.Equal:C#中相似于==

ExpressionType.NotEqual:C#中相似于!=

ExpressionType.GreaterThan:C#中相似于>

ExpressionType.GreaterThanOrEqual:C#中相似于>=

ExpressionType.LessThan:C#中相似于<

ExpressionType.LessThanOrEqual:C#中相似于<=

ExpressionType.Add:C#中相似于+

ExpressionType.AddChecked:C#中相似于+

ExpressionType.Subtract:C#中相似于-

ExpressionType.SubtractChecked:C#中相似于-

ExpressionType.Divide:C#中相似于/

ExpressionType.Multiply:C#中相似于*

ExpressionType.MultiplyChecked:C#中相似于*

2.三、编译表达式树

在表达式建立那,咱们组合建立了一个Lambda表达式,那么应该怎么使用它呢?在“表达式的解析”里面,LambdaExpression类和Expression<TDelegate>类都有一个Compile的方法,学名是Lambda表达式的委托,其实就是Lambda表达式编译函数的委托,因此咱们只须要调用他,获得的结果就是一个函数方法。

代码修改以下:

ParameterExpression numParam = Expression.Parameter(typeof(int), "num");
ConstantExpression five = Expression.Constant(5, typeof(int));
BinaryExpression numLessThanFive = Expression.LessThan(numParam, five);
Expression<Func<int, bool>> lambda1 =
    Expression.Lambda<Func<int, bool>>(
        numLessThanFive,
        new ParameterExpression[] { numParam });

Console.WriteLine($"Lambda的内容:{lambda1.ToString()}");

//表达式的编译
var func = lambda1.Compile();
Console.WriteLine($"Lambda的运行结果:{func(6)}");

运行结果

image

3、总结

这里咱们对表达式作了基本的讲解,相信你们对Lambda表达式有了初步的了解,下面咱们将继续讲解对一个表达式树的遍历。

相关文章
相关标签/搜索