C# 表达式树讲解(一)
一、前言
一直想写一篇Dpper的定制化扩展的文章,但是里面会设计到对Lambda表达式的解析,而解析Lambda表达式,就必须要知道表达式树的相关知识点。我希望能通过对各个模块的知识点或者运用能够多一点的讲解,能够帮助到园友了解得更多。虽然讲解得不全面,如果能成为打开这块的一把钥匙,也是蜗牛比较欣慰的。
表达式系列目录
C# 表达式树讲解(一)
二、表达树理解
表达式树以树形数据结构表示代码,其中每一个节点都是一种表达式,它将我们原来可以直接由代码编写的逻辑以表达式的方式存储在树状的结构里,从而可以在运行时去解析这个树,然后执行,实现动态的编辑和执行代码。在.Net 里面的Linq to SQL就是对表达式树的解析。
这里先讲解下表达式和表达式树,表达式相信大家都知道,比如x+5或者5,都可以算是表达式,而表达式树里面的树指的二叉树,也就是表达式的集合,C#中的Expression类就是表达式类。对于一棵表达式树,其叶子节点都是参数或者常数,非叶子节点都是运算符或者控制符。
2.1、表达式的创建
Lambda表达式方法:
Expression<Func<int, int,bool>> fun = (x, y) => x < y
这种方法创建出的表达式根节点类型为ExpressionType.Lambda,Type类型为返回值类型typeof(bool)
组装法(通过 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代码截图:
LambdaExpression里面的Body就是我们的表达式。
C#表达式给我们提供了丰富的表达式类,进入到LambdaExpression类里面
方法返回类型以“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.2、表达式的解析
表达式树解析
通过LambdaExpression类我们可以知道,表达式树包含:参数[Parameters],表达式树类型[NodeType],表达式[Body],返回类型[ReturnType],Lambda表达式的委托[Compile]以及Lambda表达式名称[name],如图所示:
表达式解析:
所有的表达式都包含:左节点【Left】,右节点【Right】,类型【NodeType】,不同的表达式还会有其他属性,这里的左右节点依旧是表达式。
下图是BinaryExpression表达式截图
表达式树和表达式里面的类型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.3、编译表达式树
在表达式创建那,我们组合创建了一个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)}");
运行结果
三、总结
这里我们对表达式做了基本的讲解,相信大家对Lambda表达式有了初步的了解,下面我们将继续讲解对一个表达式树的遍历。
C# 表达式树讲解(一)的更多相关文章
- C# 表达式树分页扩展(三)
一.前言 前面我们知道了表达树的基本知识,也明白了怎么遍历和修改一个表达式,这里我们就一个实际的场景来进行功能开发. 表达式系列目录 C# 表达式树讲解(一) C# 表达式树遍历(二) C# 表达式树 ...
- C# 表达式树遍历(二)
一.前言 上一篇我们对表达式树有了初步的认识,这里我们将对表达式树进行遍历,只有弄清楚了他的运行原理,我们才可以对他进行定制化修改. 表达式系列目录 C# 表达式树讲解(一) C# 表达式树遍历(二) ...
- C# 表达式树Lambda扩展(四)
一.前言 本来计算这篇文章在后面需要运用的时候写的,但是既然写到表达式的扩展呢,就一起写完吧. 看到这个标题就有一种疑问,Lambda表达式本来就是表达式树,还需要怎么扩展?那就看看下面的内容,你就知 ...
- Linq系列(7)——表达式树之ExpressionVisitor
大家好,由于今天项目升级,大家都在获最新代码,所以我又有时间在这里写点东西,跟大家分享. 在上一篇的文章中我介绍了一个dll,使大家在debug的时候可以可视化的看到ExpressionTree的Bo ...
- C# 委托、事件、表达式树理解
1.什么是委托? 委托是一种动态调用方法的类型,属于引用型. 委托是对方法的抽象和封装.委托对象实质上代表了方法的引用(即内存地址) 所有的异步都是委托 委托就是函数当入参 委托被各种语法糖遮 ...
- 再讲IQueryable<T>,揭开表达式树的神秘面纱
接上篇<先说IEnumerable,我们每天用的foreach你真的懂它吗?> 最近园子里定制自己的orm那是一个风生水起,感觉不整个自己的orm都不好意思继续混博客园了(开个玩笑).那么 ...
- [C#] C# 知识回顾 - 表达式树 Expression Trees
C# 知识回顾 - 表达式树 Expression Trees 目录 简介 Lambda 表达式创建表达式树 API 创建表达式树 解析表达式树 表达式树的永久性 编译表达式树 执行表达式树 修改表达 ...
- 轻量级表达式树解析框架Faller
有话说 之前我写了3篇关于表达式树解析的文章 干货!表达式树解析"框架"(1) 干货!表达式树解析"框架"(2) 干货!表达式树解析"框架" ...
- 用五分钟重温委托,匿名方法,Lambda,泛型委托,表达式树
这些对老一代的程序员都是老生常谈的东西,没什么新意,对新生代的程序员却充满着魅力.曾经新生代,好多都经过漫长的学习,理解,实践才能掌握委托,表达式树这些应用.今天我尝试用简单的方法叙述一下,让大家在五 ...
随机推荐
- 详解InheritableThreadLocal类的使用与原理
在Java并发编程中,InheritableThreadLocal 与 ThreadLocal 都可以用于线程间通信,不同的是 InheritableThreadLocal 继承了 ThreadLoc ...
- Java中使用RestFul接口上传图片到阿里云OSS服务器
1.接口方法 import java.io.IOException; import javax.servlet.http.HttpServletRequest; import org.springfr ...
- Could not determine type for java util List
问题场景:在实体类中需要使用List集合存储字段,启动时找不到List类型 问题解决:在字段上添加@ElementColletion(targetClass=String.class)表示是一个集合映 ...
- ASP.NET Core[源码分析篇] - WebHost
_configureServicesDelegates的承接 在[ASP.NET Core[源码分析篇] - Startup]这篇文章中,我们得知了目前为止(UseStartup),所有的动作都是在_ ...
- imwrite imshow机制
今天在做数据增强的时候,遇到一个奇怪的问题.调用imwite生成的图片,在本地用图片查看器打开的时候是正常的.但是在代码里imshow的时候是一片亮白. 代码类似如下 gaussian_img = a ...
- Ubuntu安装时出现“failed to load ldlinux.c32”
Ubuntu安装时出现“failed to load ldlinux.c32” 利用UltraISO制作了ubuntu 18.04的U盘启动,开机F12键USB启动时出现 1 2 Failed to ...
- Appium+python自动化(三十四)- 有图有真相,很美很精彩 - 屏幕截图和Android APP类型简介(超详解)
简介 在实际自动化项目运行过程中,很多时候App可以会出现各种异常,为了更好的定位问题,除了捕捉日志我们还需要对运行时的设备状态来进行截屏.从而达到一种“有图有真相”的效果. 截图方法 方法1 sav ...
- java高并发系列 - 第31天:获取线程执行结果,这6种方法你都知道?
这是java高并发系列第31篇. 环境:jdk1.8. java高并发系列已经学了不少东西了,本篇文章,我们用前面学的知识来实现一个需求: 在一个线程中需要获取其他线程的执行结果,能想到几种方式?各有 ...
- python实例:利用jieba库,分析统计金庸名著《倚天屠龙记》中人物名出现次数并排序
本实例主要用到python的jieba库 首先当然是安装pip install jieba 这里比较关键的是如下几个步骤: 加载文本,分析文本 txt=open("C:\\Users\\Be ...
- Apache—dbutils开源JDBC工具类库简介
Apache—dbutils开源JDBC工具类库简介 一.前言 commons-dbutils 是 Apache 组织提供的一个开源 JDBC工具类库,它是对JDBC的简单封装,学习成本极低,并且使用 ...