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,泛型委托,表达式树
这些对老一代的程序员都是老生常谈的东西,没什么新意,对新生代的程序员却充满着魅力.曾经新生代,好多都经过漫长的学习,理解,实践才能掌握委托,表达式树这些应用.今天我尝试用简单的方法叙述一下,让大家在五 ...
随机推荐
- 统一流控服务开源:基于.Net Core的流控服务
先前有一篇博文,梳理了流控服务的场景.业界做法和常用算法 统一流控服务开源-1:场景&业界做法&算法篇 最近完成了流控服务的开发,并在生产系统进行了大半年的验证,稳定可靠.今天整理一下 ...
- 消息中间件-activemq入门(二)
上一节我们了解了JMS规范并且知道了JMS规范的良好实现者-activemq.今天我们就去了解一下activemq的使用.另外我们应该抱着目的去学习,别忘了我们为什么要使用消息中间件:解耦系统之间的联 ...
- 详解阿里P7架构师是怎么在Spring中实现事务暂停
摘要 Spring框架是一个流行的基于轻量级控制反转容器的Java/J2EE应用框架,尤其在数据访问和事务管理方面的能力是众所周知的.Spring的声明性事务分离可以应用到任何POJO目标对象,并且包 ...
- Promise 学习心得
当了这么久码农到今天没事才开始去深究 Promise 这个对象 什么是 Promise, Promise 有什么用? 在写代码的时候多多少少都有遇见过地狱式的回调 代码看起来没问题就是有点乱,Prom ...
- 洛谷 P4401 [IOI2007]Miners 矿工配餐
题意简述 有两个矿洞,已知食物的种类(≤3)和顺序,将他们送往任一矿洞, 若一个矿洞3次食物相同,贡献1:若有2种不同食物,贡献2:若有3种不同食物,贡献3 求最大贡献 题解思路 food[i] 为当 ...
- Kubernetes容器云平台建设实践
[51CTO.com原创稿件]Kubernetes是Google开源的一个容器编排引擎,它支持自动化部署.大规模可伸缩.应用容器化管理.伴随着云原生技术的迅速崛起,如今Kubernetes 事实上已经 ...
- maven学习(1)下载和安装和初步使用(手动构建项目和自动构建项目)
1:背景 关于项目的搭建,有些人使用开发工具搭建项目,然后将项目所依赖第三方jar 复制到类路径下面,上述搭建方式没有第三方类库的依赖关系,在导入一个jar包的时候,这个jar包还可能依赖其他jar包 ...
- nginx单机1w并发优化
目录 ab工具 整体优化思路 具体的优化思路 编写脚本完成并发优化配置 性能统计工具 tips 总结 ab工具 ab -c 10000 -n 200000 http://localhost/index ...
- mybatis 中 useGeneratedKeys 和 keyProperty 含义
MyBatis如何获取插入记录的自增长字段值: 第一步: 在Mybatis Mapper文件中添加属性“useGeneratedKeys”和“keyProperty”,其中keyProperty是Ja ...
- 【数据结构】9.java源码关于HashTable
1.hashtable的内部结构 基础存储数据的hash桶由Entry结构的数组存放而entry数据结构,有hash,key和value,还有一个指向下一个节点的引用next对象 这里就和hashma ...