创建表达式树
继承 Object -> Expression -> LambdaExpression -> Expression< TDelegate>
Expression 类
- 用于创建不同类型的表达式, 有很多方法如下面两个示例:
- 如 Loop(Expression) 创建具有给定主体的 LoopExpression。
- LoopExpression 表示无限循环。 可通过“中断”退出该循环。
- GreaterThanOrEqual(Expression, Expression) 创建一个表示“大于或等于”数值比较的 BinaryExpression。
- BinaryExpression 类 表示具有二进制运算符的表达式。
- 如 Loop(Expression) 创建具有给定主体的 LoopExpression。
- Lambda方法 值得注意:创建一个表示 Lambda 表达式的表达式树。返回类型是LambdaExpression
- 参数:
- delegateType Type:一个 Type,它表示 lambda 的委托签名。
- body Expression:要将 Expression 属性设置为与其相等的 Body。
- name String lambda 的名称。 用于发出调试信息。
- tailCall Boolean 一个 Boolean,指示在编译创建的表达式时是否将应用尾调用优化。
- parameters IEnumerable< ParameterExpression> 一个 IEnumerable< T>,包含用来填充 ParameterExpression 集合的 Parameters 对象。
Expression< TDelegate> 类
- 将强类型化的 Lambda 表达式表示为表达式树形式的数据结构。 此类不能被继承。
- 作用是将参数传给LambdaExpression
- Compile 方法
- 将表达式树描述的 lambda 表达式编译为可执行代码,并生成表示 lambda 表达式的委托。
- System.Linq.Expressions.Expression<Func<int, bool>> expr = i => i < 5;
- Func<int, bool> deleg = expr.Compile();
- Update
LambdaExpression
- 由它把我们表达式的主体,名称,以及参数保存着。
- Compile() 方法 生成表示 lambda 表达式的委托。
- 该 LambdaExpression 类型以表达式树的形式表示 lambda 表达式。
- 派 Expression< TDelegate> 生 LambdaExpression 自和捕获 lambda 表达式类型的类型也可用于表示 lambda 表达式。
- 在运行时,表示 lambda 表达式的表达式树节点始终为类型 Expression< TDelegate>。
- NodeType属性值LambdaExpression为 Lambda.
- 使用 Lambda 工厂方法创建对象 LambdaExpression 。
示例 循环输入10次
// 创建 loop表达式体来包含我们想要执行的代码 表示 一个循环
LoopExpression loop = Expression.Loop(
Expression.Call(
null,
typeof(Console).GetMethod("WriteLine", new Type[] { typeof(string) }),
Expression.Constant("Hello"))
);
// 创建一个代码块表达式包含我们上面创建的loop表达式,其中Expression.Block方法的参数是一个循环
BlockExpression block = Expression.Block(loop);
// 通过lambda方法 创建一个表示 Lambda 表达式的表达式树。
Expression<Action> lambdaExpression = Expression.Lambda<Action>(block);
//通过Compile 方法生成表示 lambda 表达式的委托。最后通过Invoke方法调用委托
lambdaExpression.Compile().Invoke();
// 创建 loop表达式体来包含我们想要执行的代码
using System.Linq.Expressions;
//示一个标签,可以将该标签放置在任何 Expression 上下文中。 如果已跳转到该标签,则它将获取由对应的 GotoExpression 提供的值。
//否则,它接收 DefaultValue 中的值。 如果 Type 等于 System.Void,则不应提供值。
LabelTarget labelBreak = Expression.Label();
//表示一个命名的参数表达式
ParameterExpression loopIndex = Expression.Parameter(typeof(int), "index");
//创建一个 BlockExpression,其中包含给定的变量和表达式。
BlockExpression block = Expression.Block(
new[] { loopIndex },
// 创建一个表示赋值运算的 BinaryExpression。 声明了一个 初始化loopIndex =1
Expression.Assign(loopIndex, Expression.Constant(1)),
//1.创建 loop表达式体来包含我们想要执行的代码 表示 一个循环,
Expression.Loop(
Expression.IfThenElse(
// if 的判断逻辑
Expression.LessThanOrEqual(loopIndex, Expression.Constant(10)),
// 判断逻辑通过的代码
Expression.Block(
//Call 表达式体包含对静态方法或实例方法的调用。
Expression.Call(
null,
typeof(Console).GetMethod("WriteLine", new Type[] { typeof(string) }),
Expression.Constant("Hello")),
Expression.PostIncrementAssign(loopIndex)),
// 判断不通过的代码
Expression.Break(labelBreak)
), labelBreak));
// 通过lambda方法 创建一个表示 Lambda 表达式的表达式树。
Expression<Action> lambdaExpression = Expression.Lambda<Action>(block);
//通过Compile 方法生成表示 lambda 表达式的委托。最后通过Invoke方法调用委托
lambdaExpression.Compile().Invoke();
//block的Debuger View
//.Block(System.Int32 $index) {
// $index = 1;
// .Loop {
// .If($index <= 10) {
// .Block() {
// .Call System.Console.WriteLine("Hello");
// $index++
// }
// } .Else {
// .Break #Label1 { }
// }
// }
// .LabelTarget #Label1:
//}
//Lambda方法调用后 lambdaExpression的 Debuger View
//.Lambda #Lambda1<System.Action>() {
// .Block(System.Int32 $index) {
// $index = 1;
// .Loop {
// .If($index <= 10) {
// .Block() {
// .Call System.Console.WriteLine("Hello");
// $index++
// }
// } .Else {
// .Break #Label1 { }
// }
// }
// .LabelTarget #Label1:
// }
//}
// 直接返回常量值
ConstantExpression ce1 = Expression.Constant(10);
// 直接用我们上面创建的常量表达式来创建表达式树
Expression<Func<int>> expr1 = Expression.Lambda<Func<int>>(ce1);
Console.WriteLine(expr1.Compile().Invoke());
// 10
// --------------在方法体内创建变量,经过操作之后再返回------------------
//返回的值所在的表达式写在block的最后一个参数
// 1.创建方法体表达式 2.在方法体内声明变量并附值 3. 返回该变量
ParameterExpression param2 = Expression.Parameter(typeof(int));
BlockExpression block2 = Expression.Block(
new[] { param2 },
Expression.AddAssign(param2, Expression.Constant(20)),
param2
);
Expression<Func<int>> expr2 = Expression.Lambda<Func<int>>(block2);
Console.WriteLine(expr2.Compile().Invoke());
// 20
// -------------利用GotoExpression返回值-----------------------------------
// 创建一个 LabelTarget,它表示具有 void 类型但没有名称的标签 用于表示 GotoExpression 的目标。
LabelTarget returnTarget = Expression.Label(typeof(Int32));
//创建一个 LabelExpression,它表示具有给定默认值的标签
//表示一个标签,可以将该标签放置在任何 Expression 上下文中。
//如果已跳转到该标签,则它将获取由对应的 GotoExpression 提供的值。
//否则,它接收 DefaultValue 中的值。 如果 Type 等于 System.Void,则不应提供值。
LabelExpression returnLabel = Expression.Label(returnTarget, Expression.Constant(100, typeof(Int32)));
// 为输入参加+10之后返回
ParameterExpression inParam3 = Expression.Parameter(typeof(int));
BlockExpression block3 = Expression.Block(
Expression.AddAssign(inParam3, Expression.Constant(10)),
//创建一个表示 return 语句的 GotoExpression。 可以指定在跳转时传递给标签的值。
Expression.Return(returnTarget, inParam3),
returnLabel
);
Expression<Func<int, int>> expr3 = Expression.Lambda<Func<int, int>>(block3, inParam3);
Console.WriteLine(expr3.Compile().Invoke(20));
// 30
//简单的switch case 语句 来返回值
ParameterExpression genderParam = Expression.Parameter(typeof(int));
SwitchExpression switchExpression = Expression.Switch(
genderParam,
Expression.Constant("不详"),//默认值
Expression.SwitchCase(Expression.Constant("男"), Expression.Constant(1)),
Expression.SwitchCase(Expression.Constant("女"), Expression.Constant(0))
//你可以将上面的Expression.Constant替换成其它复杂的表达式,ParameterExpression, BinaryExpression等, 这也是表达式灵活的地方,
//因为归根结底它们都是继承自Expression, 而基本上我们用到的地方都是以基类作为参数类型接受的,所以我们可以传递任意类型的表达式。
);
Expression<Func<int, string>> expr4 = Expression.Lambda<Func<int, string>>(switchExpression, genderParam);