饮水思源
本文并非原创而是下面网址的一个学习笔记
https://docs.microsoft.com/en-us/dotnet/csharp/programming-guide/concepts/expression-trees/index
Overview
上一文中介绍了语句Lambda和表达式Lambda,关于语句Lambda没有什么好说的地方,关于表达式Lambda 可以说是大有文章,本着来详细的说一说 表达式树。
- 可以基于Lambda表达式创建创建表达式树,也可以使用 System.Linq.Expressions 命名空间中的类手动创建表达式树。
从Lambda表达式创建表达式树
当Lambda表达式分配给Expression
类型变量的时候,编译器会将,Lambda表达式构建成表达式树。 编译器只能从表达式Lambda生成表达式数,不能解析语句Lambda为表达式树。
Expression<Func<int, bool>> expression = x => x > 10;
使用API创建时表达式树
使用API,创建表达式树,需要用到Expression类,此类总包含大量的工厂方法,用于创建各种各样的表达式树节点,如:
- 表示变量或者参数的 ParameterExpression
- 表示方法调用的 MethodCallExpression
其中,还有好多类似的类型,和方法,这些类型都继承自 Expression 抽象类。
比如, 创建一个 x => x>10; lambda 表达式的表达式树
using System;
using System.Linq.Expressions;
static void Main(string[] args)
{
//x => x>10
//创建代表x的变量表达式
ParameterExpression peParameter = Expression.Parameter(typeof(int), "x");
//创建代表10 的常量表达式
ParameterExpression peRight = Expression.Parameter(typeof(int), "10");
//创建大于运算的表达式
BinaryExpression be = Expression.GreaterThan(peParameter, peRight);
//构建为表达式树
Expression<Func<int, bool>> expression = Expression.Lambda<Func<int, bool>>(be, new ParameterExpression[] { peParameter });
Console.WriteLine(expression.ToString());
//输出结果为: x => (x > 10)
}
更为复杂的表达式树
在.NET Framework 4.0 或者个更高的版本中,还表达式树API还支持流程控制操作,如果Try-catch
和 If
语句块。通过这些API,可以创建,比编译器,从表达式Lambda 创建的表达式树更复杂的API。
比如说一个阶乘运算
static void Factorial()
{
ParameterExpression value = Expression.Parameter(typeof(int), "value");
//创建一个表达式,用来存在本地变量
ParameterExpression result = Expression.Parameter(typeof(int));
//跳转标识表达式
LabelTarget label = Expression.Label(typeof(int));
//语句块表达式
BlockExpression be = Expression.Block(
//添加一个局部变量
new[] { result },
//赋值操作
Expression.Assign(result, Expression.Constant(1)),
//循环结构
Expression.Loop(
Expression.IfThenElse(
//判断条件 如果value > 1
Expression.GreaterThan(value, Expression.Constant(1)),
//执行乘法操作 result *= value--;
Expression.MultiplyAssign(result, Expression.PostDecrementAssign(value)),
//退出循环跳转到Label
Expression.Break(label, result)),
label));
int r = Expression.Lambda<Func<int, int>>(be, value).Compile()(10);
Console.WriteLine(r);
//r=120
}
解析表达式树
/// <summary>
/// 解析表达式
/// </summary>
public static void ParseExpression()
{
Expression<Func<int, bool>> etree = x => x > 10;
//获取参数
ParameterExpression pe = etree.Parameters[0];
//获取> 运算所对应的表达式
BinaryExpression be = etree.Body as BinaryExpression;
//获取 > 运算左边的表达式
ParameterExpression left = be.Left as ParameterExpression;
//获取 > 运算右边的表达式
ConstantExpression right = be.Right as ConstantExpression;
Console.WriteLine("表达式树解析为 : {0} => {1} {2} {3}", pe.Name, left.Name, be.NodeType, right.Value);
//表达式树解析为 : x => x GreaterThan 10
}
表达式不可变性
Expression trees should be immutable. This means that if you want to modify an expression tree, you must construct a new expression tree by copying the existing one and replacing nodes in it. You can use an expression tree visitor to traverse the existing expression tree. For more information, see How to: Modify Expression Trees (C#).
编译表达式树
/// <summary>
/// 将表达式树编译为委托
/// </summary>
public static void Compile()
{
//新建一个表达式树
Expression<Func<int, bool>> eTree = x => x > 10;
/*
Compile() 方法,将被表达式树描述的Lambda表达式,编译为可执行的代码并且行生表达该Lambda表达式的委托。
*/
//将表达式树编译为委托
Func<int, bool> f = eTree.Compile();
bool flag = f.Invoke(100);
Console.WriteLine(flag);
//输出结果 True
}