C# 知识回顾 - 表达式树 Expression Trees
C# 知识回顾 - 表达式树 Expression Trees
目录
简介
表达式树以树形数据结构表示代码,其中每一个节点都是一种表达式,比如方法调用和 x < y 这样的二元运算等。
表达式树还能用于动态语言运行时 (DLR) 以提供动态语言和 .NET Framework 之间的互操作性。
一、Lambda 表达式创建表达式树
若 lambda 表达式被分配给 Expression<TDelegate> 类型的变量,则编译器可以发射代码以创建表示该 lambda 表达式的表达式树。
C# 编译器只能从表达式 lambda (或单行 lambda)生成表达式树。
下列代码示例使用关键字 Expression创建表示 lambda 表达式:
1 Expression<Action<int>> actionExpression = n => Console.WriteLine(n);
2 Expression<Func<int, bool>> funcExpression1 = (n) => n < 0;
3 Expression<Func<int, int, bool>> funcExpression2 = (n, m) => n - m == 0;
二、API 创建表达式树
通过 API 创建表达式树需要使用 Expression 类
下列代码示例展示如何通过 API 创建表示 lambda 表达式:num => num == 0

1 //通过 Expression 类创建表达式树
2 // lambda:num => num == 0
3 ParameterExpression pExpression = Expression.Parameter(typeof(int)); //参数:num
4 ConstantExpression cExpression = Expression.Constant(0); //常量:0
5 BinaryExpression bExpression = Expression.MakeBinary(ExpressionType.Equal, pExpression, cExpression); //表达式:num == 0
6 Expression<Func<int, bool>> lambda = Expression.Lambda<Func<int, bool>>(bExpression, pExpression); //lambda 表达式:num => num == 0

代码使用 Expression 类的静态方法进行创建。
三、解析表达式树
下列代码示例展示如何分解表示 lambda 表达式 num => num == 0 的表达式树。

1 Expression<Func<int, bool>> funcExpression = num => num == 0;
2
3 //开始解析
4 ParameterExpression pExpression = funcExpression.Parameters[0]; //lambda 表达式参数
5 BinaryExpression body = (BinaryExpression)funcExpression.Body; //lambda 表达式主体:num == 0
6
7 Console.WriteLine($"解析:{pExpression.Name} => {body.Left} {body.NodeType} {body.Right}");


四、表达式树永久性
五、编译表达式树
Expression<TDelegate> 类型提供了 Compile 方法以将表达式树表示的代码编译成可执行委托。

1 //创建表达式树
2 Expression<Func<string, int>> funcExpression = msg => msg.Length;
3 //表达式树编译成委托
4 var lambda = funcExpression.Compile();
5 //调用委托
6 Console.WriteLine(lambda("Hello, World!"));
7
8 //语法简化
9 Console.WriteLine(funcExpression.Compile()("Hello, World!"));


六、执行表达式树
执行表达式树可能会返回一个值,也可能仅执行一个操作(例如调用方法)。

1 const int n = 1;
2 const int m = 2;
3
4 //待执行的表达式树
5 BinaryExpression bExpression = Expression.Add(Expression.Constant(n), Expression.Constant(m));
6 //创建 lambda 表达式
7 Expression<Func<int>> funcExpression = Expression.Lambda<Func<int>>(bExpression);
8 //编译 lambda 表达式
9 Func<int> func = funcExpression.Compile();
10
11 //执行 lambda 表达式
12 Console.WriteLine($"{n} + {m} = {func()}");


七、修改表达式树
该类继承 ExpressionVisitor 类,通过 Visit 方法间接调用 VisitBinary 方法将 != 替换成 ==。基类方法构造类似于传入的表达式树的节点,但这些节点将其子目录树替换为访问器递归生成的表达式树。

1 internal class Program
2 {
3 private static void Main(string[] args)
4 {
5 Expression<Func<int, bool>> funcExpression = num => num == 0;
6 Console.WriteLine($"Source: {funcExpression}");
7
8 var visitor = new NotEqualExpressionVisitor();
9 var expression = visitor.Visit(funcExpression);
10
11 Console.WriteLine($"Modify: {expression}");
12
13 Console.Read();
14 }
15
16 /// <summary>
17 /// 不等表达式树访问器
18 /// </summary>
19 public class NotEqualExpressionVisitor : ExpressionVisitor
20 {
21 public Expression Visit(BinaryExpression node)
22 {
23 return VisitBinary(node);
24 }
25
26 protected override Expression VisitBinary(BinaryExpression node)
27 {
28 return node.NodeType == ExpressionType.Equal
29 ? Expression.MakeBinary(ExpressionType.NotEqual, node.Left, node.Right) //重新弄个表达式:用 != 代替 ==
30 : base.VisitBinary(node);
31 }
32 }
33 }


八、调试
8.1 参数表达式
1 ParameterExpression pExpression1 = Expression.Parameter(typeof(string));
2 ParameterExpression pExpression2 = Expression.Parameter(typeof(string), "msg");

图8-1

图8-2
从 DebugView 可知,如果参数没有名称,则会为其分配一个自动生成的名称。
1 const int num1 = 250;
2 const float num2 = 250;
3
4 ConstantExpression cExpression1 = Expression.Constant(num1);
5 ConstantExpression cExpression2 = Expression.Constant(num2);

图8-3

图8-4
从 DebugView 可知,float 比 int 多了个后缀 F。
1 Expression lambda1 = Expression.Lambda<Func<int>>(Expression.Constant(250));
2 Expression lambda2 = Expression.Lambda<Func<int>>(Expression.Constant(250), "CustomName", null);

图8-5

图8-6
观察 DebugView ,如果 lambda 表达式没有名称,则会为其分配一个自动生成的名称。
C# 知识回顾 - 表达式树 Expression Trees的更多相关文章
- [C#] C# 知识回顾 - 表达式树 Expression Trees
C# 知识回顾 - 表达式树 Expression Trees 目录 简介 Lambda 表达式创建表达式树 API 创建表达式树 解析表达式树 表达式树的永久性 编译表达式树 执行表达式树 修改表达 ...
- 表达式树(Expression Tree)
饮水思源 本文并非原创而是下面网址的一个学习笔记 https://docs.microsoft.com/en-us/dotnet/csharp/programming-guide/concepts/e ...
- 表达式树 Expression
转载泛型方法动态生成表达式树 Expression public string GetGridJSON(TraderInfo model) { IQueryable<TraderInfo> ...
- C# 表达式树 Expression
表达式树是定义代码的数据结构. 它们基于编译器用于分析代码和生成已编译输出的相同结构. 几种常见的表达式 BinaryExpression 包含二元运算符的表达式 BinaryExpression b ...
- 泛型方法动态生成表达式树 Expression
public string GetGridJSON(TraderInfo model) { IQueryable<TraderInfo> Temp = db.TraderInfo; if ...
- jQuery find() 搜索所有段落中的后代 C# find() 第一个匹配元素 Func 有返回值 Action是没有返回值 Predicate 只有一个参数且返回值为bool 表达式树Expression
所有p后代span Id为 TotalProject 的 select 标签 的后代 option标签 为选中的 text using System; using System.Collections ...
- 利用表达式树Expression优化反射性能
最近做了一个.Net Core环境下,基于NPOI的Excel导入导出以及Word操作的服务封装,涉及到大量反射操作,在性能优化过程中使用到了表达式树,记录一下. Excel导入是相对比较麻烦的一块, ...
- 表达式树Expression
Expression表达式树动态查询 在进行数据列表的查询中,我们通常会使用两种方式进行查询: linq查询 数据库sql语句查询 这样固然可以实现查询,本人之前也都是这么做的,因为查询的条件很少.使 ...
- Func委托与表达式树Expression
最近在写ORM框架,其中遇到一个难点,就是作为框架调用方如何将查询条件传入框架内.其中就用到了Expression. Func委托 要Expression先要了解Func委托,Func委托的样式是: ...
随机推荐
- 在CentOS7中搭建Zookeeper集群
前几天装了CentOS7.并安装了一些基本的工具,现在我手上有三台机器:分别是master,slave1,slave2. 今天我将搭建zookeeper,使用的版本是zookeeper-3.4.11. ...
- SpaceVim 语言模块 lua
原文连接: https://spacevim.org/cn/layers/lang/lua/ 模块简介 启用模块 快捷键 交互式编程 运行当前脚本 模块简介 这一模块为在 SpaceVim 中进行 l ...
- 20145202马超 2016-2017-2 《Java程序设计》第11周学习总结
20145202马超 2016-2017-2 <Java程序设计>第11周学习总结 教材学习内容总结 XX 教材学习中的问题和解决过程 教材学习有问题先去https://shimo.im/ ...
- 北京Uber优步司机奖励政策(1月29日)
滴快车单单2.5倍,注册地址:http://www.udache.com/ 如何注册Uber司机(全国版最新最详细注册流程)/月入2万/不用抢单:http://www.cnblogs.com/mfry ...
- 武汉Uber优步司机奖励政策(1月11日~1月17日)
滴快车单单2.5倍,注册地址:http://www.udache.com/ 如何注册Uber司机(全国版最新最详细注册流程)/月入2万/不用抢单:http://www.cnblogs.com/mfry ...
- jQuery个人总结
选择 1. end()的使用 $('div') .find('h3') .eq(2) .html('Hello') .end() //退回到选中所有的h3元素的那一步 .eq(0) //选中第一个h3 ...
- 虚拟机ubuntu使用串口
1. 电脑的串口默认是在windows系统上,需要把串口转到ubuntu上面,按照下面的步骤先 2. 找到需要使用的串口 3. 在VMWARE里面连接该串口 或者使用方法 4. 成功之后,检查一下ls ...
- WebDriver--定位元素的8种方式
在UI层面的自动化测试开发中,元素的定位与操作是基础,也是经常遇到的困难所在.webdriver提供了8种定位: 1. id定位:find_element_by_id("id值") ...
- 汽车VIN码识别/汽车车架号OCR识别,移动端VIN码识别,OCR扫描工具
本文推荐了一项汽车VIN码自动识别技术,用户通过手机“扫一扫”的简单操作,就可以快速识别VIN码,查询到车辆的详细信息,为汽修汽配.二手车交易.车辆监管.查勘理赔提高工作效率. VIN是英文Vehic ...
- Siki_Unity_2-1_API常用方法和类详细讲解(下)
Unity 2-1 API常用方法和类详细讲解(下) 任务101&102:射线检测 射线origin + direction:射线检测:射线是否碰撞到物体 (物体需要有碰撞器),碰撞物体的信息 ...