[C#] C# 知识回顾 - 表达式树 Expression Trees
C# 知识回顾 - 表达式树 Expression Trees
目录
简介
表达式树以树形数据结构表示代码,其中每一个节点都是一种表达式,比如方法调用和 x < y 这样的二元运算等。
表达式树还能用于动态语言运行时 (DLR) 以提供动态语言和 .NET Framework 之间的互操作性。
一、Lambda 表达式创建表达式树
若 lambda 表达式被分配给 Expression<TDelegate> 类型的变量,则编译器可以发射代码以创建表示该 lambda 表达式的表达式树。
C# 编译器只能从表达式 lambda (或单行 lambda)生成表达式树。
下列代码示例使用关键字 Expression创建表示 lambda 表达式:
Expression<Action<int>> actionExpression = n => Console.WriteLine(n);
Expression<Func<int, bool>> funcExpression1 = (n) => n < ;
Expression<Func<int, int, bool>> funcExpression2 = (n, m) => n - m == ;
二、API 创建表达式树
通过 API 创建表达式树需要使用 Expression 类
下列代码示例展示如何通过 API 创建表示 lambda 表达式:num => num == 0
//通过 Expression 类创建表达式树
// lambda:num => num == 0
ParameterExpression pExpression = Expression.Parameter(typeof(int)); //参数:num
ConstantExpression cExpression = Expression.Constant(); //常量:0
BinaryExpression bExpression = Expression.MakeBinary(ExpressionType.Equal, pExpression, cExpression); //表达式:num == 0
Expression<Func<int, bool>> lambda = Expression.Lambda<Func<int, bool>>(bExpression, pExpression); //lambda 表达式:num => num == 0
代码使用 Expression 类的静态方法进行创建。
三、解析表达式树
下列代码示例展示如何分解表示 lambda 表达式 num => num == 0 的表达式树。
Expression<Func<int, bool>> funcExpression = num => num == ;
//开始解析
ParameterExpression pExpression = funcExpression.Parameters[]; //lambda 表达式参数
BinaryExpression body = (BinaryExpression)funcExpression.Body; //lambda 表达式主体:num == 0
Console.WriteLine($"解析:{pExpression.Name} => {body.Left} {body.NodeType} {body.Right}");

四、表达式树永久性
五、编译表达式树
Expression<TDelegate> 类型提供了 Compile 方法以将表达式树表示的代码编译成可执行委托。
//创建表达式树
Expression<Func<string, int>> funcExpression = msg => msg.Length;
//表达式树编译成委托
var lambda = funcExpression.Compile();
//调用委托
Console.WriteLine(lambda("Hello, World!")); //语法简化
Console.WriteLine(funcExpression.Compile()("Hello, World!"));

六、执行表达式树
执行表达式树可能会返回一个值,也可能仅执行一个操作(例如调用方法)。
const int n = ;
const int m = ; //待执行的表达式树
BinaryExpression bExpression = Expression.Add(Expression.Constant(n), Expression.Constant(m));
//创建 lambda 表达式
Expression<Func<int>> funcExpression = Expression.Lambda<Func<int>>(bExpression);
//编译 lambda 表达式
Func<int> func = funcExpression.Compile(); //执行 lambda 表达式
Console.WriteLine($"{n} + {m} = {func()}");

七、修改表达式树
该类继承 ExpressionVisitor 类,通过 Visit 方法间接调用 VisitBinary 方法将 != 替换成 ==。基类方法构造类似于传入的表达式树的节点,但这些节点将其子目录树替换为访问器递归生成的表达式树。
internal class Program
{
private static void Main(string[] args)
{
Expression<Func<int, bool>> funcExpression = num => num == ;
Console.WriteLine($"Source: {funcExpression}"); var visitor = new NotEqualExpressionVisitor();
var expression = visitor.Visit(funcExpression); Console.WriteLine($"Modify: {expression}"); Console.Read();
} /// <summary>
/// 不等表达式树访问器
/// </summary>
public class NotEqualExpressionVisitor : ExpressionVisitor
{
public Expression Visit(BinaryExpression node)
{
return VisitBinary(node);
} protected override Expression VisitBinary(BinaryExpression node)
{
return node.NodeType == ExpressionType.Equal
? Expression.MakeBinary(ExpressionType.NotEqual, node.Left, node.Right) //重新弄个表达式:用 != 代替 ==
: base.VisitBinary(node);
}
}
}

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

图8-1

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

图8-3

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

图8-5

图8-6
观察 DebugView ,如果 lambda 表达式没有名称,则会为其分配一个自动生成的名称。
【原文链接】http://www.cnblogs.com/liqingwen/p/5868688.html
【参考】微软官方文档
[C#] C# 知识回顾 - 表达式树 Expression Trees的更多相关文章
- 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委托的样式是: ...
随机推荐
- 从零开始编写自己的C#框架(24)——测试
导航 1.前言 2.不堪回首的开发往事 3.测试推动开发的成长——将Bug消灭在自测中 4.关于软件测试 5.制定测试计划 6.编写测试用例 7.执行测试用例 8.发现并提交Bug 9.开发人员修复B ...
- android键盘
在应用的开发过程中有不少的情况下会用到自定义键盘,例如支付宝的支付密码的输入,以及类似的场景.android系统给开发者们提供了系统键盘,KeyboardView,其实并不复杂,只是有些开发者不知道罢 ...
- SharpMap简析
1.背景 因为项目需求,需要基于开源项目来对SHP进行相关操作.涉及到的主要功能就是加载SHP读取其中的属性信息和几何信息.于是选择了Sharpmap来进行,在使用中对其相关功能做了初步了解,做个总结 ...
- 小兔JS教程(三)-- 彻底攻略JS回调函数
这一讲来谈谈回调函数. 其实一句话就能概括这个东西: 回调函数就是把一个函数当做参数,传入另一个函数中.传进去的目的仅仅是为了在某个时刻去执行它. 如果不执行,那么你传一个函数进去干嘛呢? 就比如说对 ...
- iOS微信里打开app,Universal Links
这两天在弄分享,从第三方应用或者浏览器打开自己app的东西 传统的方式是通过URL Scheme的方式,但是iOS9以后又出了新的更完美的方式Universal Links. 传统的URL Schem ...
- 【工具使用】mac电脑使用技巧
本文地址 分享提纲: 1. mac命令行和finder的交互 2. 一些mac的插件 3. 一些开发的配置 1.mac命令行和findder交互 1)命令行中打开当前文件夹: o ...
- 【转】组件化的Web王国
本文由 埃姆杰 翻译.未经许可,禁止转载!英文出处:Future Insights. 内容提要 使用许多独立组件构建应用程序的想法并不新鲜.Web Component的出现,是重新回顾基于组件的应用程 ...
- python性能检测工具整理
python 运行后出现core dump产生core.**文件,可通过gdb来调试 Using GDB with a core dump having found build/python/core ...
- TCP三次握手图解
- 用 eric6 与 PyQt5 实现python的极速GUI编程(系列04)---- PyQt5自带教程:地址簿(address book)
[引子] 在PyQt5自带教程中,地址簿(address book)程序没有完全实现界面与业务逻辑分离. 本文我打算用eric6+PyQt5对其进行改写,以实现界面与逻辑完全分离. [概览] 1.界面 ...