表达式树(Expression Trees)
[翻译]表达式树(Expression Trees)
原文地址:https://docs.microsoft.com/en-us/dotnet/csharp/programming-guide/concepts/expression-trees/index
表达式树展示的是代码的树形结构,每一个节点都是一个表达式,例如:调用一个方法或是调用一个二元运算表达式比如 x < y
你可以通过表达式树来编译和运行代码。这意味着能动态修改运行的代码,就好比在数据库中运行LINQ以一个变量的形式查询数据和创建一个动态的查询语句。关于表达式树在LINQ的更多使用信息详见How to: Use Expression Trees to Build Dynamic Queries (C#).
表达式树也被用于DLR(动态语言运行时),提供DLR与.NET Framework之间的互操作性,使编译器解析(Emit)表达式树,而不是MSIL。关于DLR更多信息详细详见Dynamic Language Runtime Overview.
你可以用C#/VB编译器在你的lambda表达式变量的基础上生成一个表达式树,或者你可以通过使用在System.Linq.Expressions命名空间创建表达式树.
从Lambda表达式创建表达式树
当一个lambda表达式被分配到类型为Expression的的一个变量时,编译器会解析生成代码创建一个表达式树来表示这个lambda .
C#编译器能从lambda生成表达式树(或者从一个单行的lambda)。但它不能转换成lambda声明(或多行lambda)。更多关于lambda信息见Lambda Expressions.
下面的代码例子说明了如何用C#来生成一个表达式树来表示一个lambda表达式: num => num < 5
Expression<Func<int, bool>> lambda = num => num < 5;
通过API创建表达式树
使用微软提供的API——Expression这个类来创建表达式树。这个类包括了创建指定类型表达式树节点的静态工厂方法,例如, ParameterExpression它代表一个参数或者变量,又如MethodCallExpression,它代表一个方法调用。ParameterExpression, MethodCallExpression以及其他的指定类型的表达式树都在System.Linq.Expressions命名空间下。这些类都继承自 Expression抽象类.
下面的代码展示如何用API创建表达式树来表示一个lambda表达式num => num < 5
// 在你的代码文件添加引用:
// using System.Linq.Expressions;
// 为lambda表达式num => num < 5手动生成表达式树
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 });
在.NET Framework4.0之后,表达式树API也支持分配和控制流表达式,例如循环,条件判断块以及异常捕捉块(try-catch)。通过API,你可以创建比编译器通过从lambda表达式创建的更加复杂的表达式树。下面的这个例子展示了如何创建一个表达式树来表示一个数的阶乘(factorial of number).
//创建一个参数表达式
ParameterExpression value = Expression.Parameter(typeof(int), "value");
//创建一个表达式表示本地变量
ParameterExpression result = Expression.Parameter(typeof(int), "result");
//创建标签从循环跳到指定标签
LabelTarget label = Expression.Label(typeof(int));
//创建方法体
BlockExpression block = Expression.Block(
//添加本地变量
new[] { result },
//为本地变量赋值一个常量
Expression.Assign(result, Expression.Constant(1)),
//循环
Expression.Loop(
//添加循环条件
Expression.IfThenElse(
//条件:value > 1
Expression.GreaterThan(value, Expression.Constant(1)),
//if true
Expression.MultiplyAssign(result, Expression.PostDecrementAssign(value)),
//if false
Expression.Break(label, result)
),
label
)
);
int facotorial = Expression.Lambda<Func<int, int>>(block, value).Compile()(5);
Console.WriteLine(factorial);
// 输出 120.
更多关于详见Generating Dynamic Methods with Expression Trees in Visual Studio 2010,也支持后续VS版本.
解析表达式树(Parsing Expression Trees)
下面的代码示例演示了如何将表达式树表示为lambda表达式num => num < 5,可以被分解为部分。
public void DecomposedExpressionTrees()
{
//创建一个表达式树
Expression<Func<int, bool>> exprTree = num => num < 5;
//分解表达式
ParameterExpression param = (ParameterExpression)exprTree.Parameters[0];
//num < 5
BinaryExpression operation = (BinaryExpression)exprTree.Body;
ParameterExpression left = (ParameterExpression)operation.Left;
ConstantExpression right = (ConstantExpression)operation.Right;
Console.WriteLine("Decomposed expression: {0} => {1} {2} {3}",
param.Name, left.Name, operation.NodeType, right.Value);
}
表达式树的不变性(Immutability of Expression Trees)
表达式树应该是不可变的。这意味着如果你想修改表达式树,那么你必须重新已经存在的构造表达式树并替换其某个节点。你可以使用表达式树访问器(ExpressionVisitor)遍历表达式树。更多这方面信息详见How to: Modify Expression Trees (C#).
编译表达式树
泛型 Expression 类型提供一个 Compile方法来将表达式树所表示的代码编译成可执行的委托。
下面这段代码显示如何编译表达式树和运行结果代码
public void ComplieExpressTrees()
{
//创建一个表达式树
Expression<Func<int, bool>> expr = num => num < 5;
//编译表达式树为委托
Func<int, bool> result = expr.Compile();
//调用委托并写结果到控制台
Console.WriteLine(result(4));
//也可以使用简单的语法来编译运行表达式树
Console.WriteLine(expr.Compile()(4));
//结果一样
}
更多关于如何运行表达式树信息,详见How to: Execute Expression Trees (C#).
表达式树(Expression Trees)的更多相关文章
- [C#] C# 知识回顾 - 表达式树 Expression Trees
C# 知识回顾 - 表达式树 Expression Trees 目录 简介 Lambda 表达式创建表达式树 API 创建表达式树 解析表达式树 表达式树的永久性 编译表达式树 执行表达式树 修改表达 ...
- 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# 一些代码小结--UI操作
C# 一些代码小结--UI操作 使用控件名调用控件 object obj = this.GetType().GetField("控件名", System.Reflection.Bi ...
- 4.翻译:EF基础系列--EF架构
原文地址:http://www.entityframeworktutorial.net/EntityFramework-Architecture.aspx 下面的图形,展示了EF的总体架构: 让我们来 ...
- ceph 源码安装 configure: error: "Can't find boost spirit headers"
问题:configure: error: "Can't find boost spirit headers" 解决: 推荐:sudo apt-get install libboos ...
- nginx-1.服务器是什么
服务器相信很多电脑爱好者都听过或者了解一些,一般我们很难看到真正的服务器,因为服务器一般均放置在机房重点,闲人一般均是免进的.比如我们每天浏览的网站.玩的游戏等,所有的数据均存在服务器,服务器一般都在 ...
- JQuery 知识
1.修改标签内容: *html( ) 相当于innerHTML * text( ) 相当于innerText 2.属性操作: *attr( ) 读/写/添加/设置属性 *removeAttr ...
- java的基本数据类型--四类八种
java的数据类型 1.分为基本数据类型和引用数据类型 基本数据类型的分类:整数型: byte 占用一个字节 范围-128-127 short 占用两个字节 -2^15~2^15-1 int ...
- spring cloud学习(二) 调用服务
spring-cloud调用服务有两种方式,一种是Ribbon+RestTemplate, 另外一种是Feign. Ribbon是一个基于HTTP和TCP客户端的负载均衡器,其实feign也使用了ri ...
- Vue+WebSocket+ES6+Canvas 制作「你画我猜」小游戏
Vue+WebSocket+ES6+Canvas 制作「你画我猜」小游戏 转载 来源:jrainlau 链接:https://segmentfault.com/a/1190000005804860 项 ...
- odoo开发笔记 -- context上下文
字段级别 视图级别 窗口动作级别
- Redhat/CentOS 制作本地yum源
一.制作本地yum源的场景有: (1) 操作系统ISO文件是通过光驱读取的 (2) 操作系统ISO文件是通过USB设备挂载的 (3) 操作系统ISO文件是被上传到本地文件夹的形式 二. 这3种配置方式 ...