表达式树练习实践:C# 循环
C# 提供了以下几种循环类型。
循环类型 | 描述 |
---|---|
while 循环 | 当给定条件为真时,重复语句或语句组。它会在执行循环主体之前测试条件。 |
for/foreach 循环 | 多次执行一个语句序列,简化管理循环变量的代码。 |
do...while 循环 | 除了它是在循环主体结尾测试条件外,其他与 while 语句类似。 |
嵌套循环 | 您可以在 while、for 或 do..while 循环内使用一个或多个循环。 |
当然,还有以下用于控制循环的语句
控制语句 | 描述 |
---|---|
break 语句 | 终止 loop 或 switch 语句,程序流将继续执行紧接着 loop 或 switch 的下一条语句。 |
continue 语句 | 引起循环跳过主体的剩余部分,立即重新开始测试条件。 |
LabelTarget
LabelTarget 是用于创建循环标记的。
无论是 for 还是 while ,平时编写循环时,都需要有跳出循环的判断,有时需要某个参数自增自减并且作为判断依据。
C# 表达式树里面是没有专门表示 for /while 的,里面只有一个 Loop。看一下Loop 生成的表达式树
.Lambda #Lambda1<System.Func`1[System.Int32]>() {
.Block(System.Int32 $x) {
$x = 0;
.Loop {
.If ($x < 10) {
$x++
} .Else {
.Break #Label1 { $x }
}
}
.LabelTarget #Label1:
}
}
要实现循环控制,有 break,contauine 两种 Expression:
public static GotoExpression Break(LabelTarget target, Type type);
public static GotoExpression Break(LabelTarget target, Expression value);
public static GotoExpression Break(LabelTarget target);
public static GotoExpression Break(LabelTarget target, Expression value, Type type);
public static GotoExpression Continue(LabelTarget target, Type type);
public static GotoExpression Continue(LabelTarget target);
所以,要实现循环控制,必须要使用 LabelTarget,不然就无限循环了。
要理解 LabelTarget ,最好的方法是动手做。
for / while 循环
Expression.Loop 用于创建循环,包括 for 和 while,定义如下
public static LoopExpression Loop(Expression body, LabelTarget @break, LabelTarget @continue);
System.Linq.Expressions.LoopExpression.
public static LoopExpression Loop(Expression body);
public static LoopExpression Loop(Expression body, LabelTarget @break);
表达式树里面的循环,只有 Loop,无 for / while 的区别。
那么,我们来一步步理解 Loop 循环和 LabelTarget;
无限循环
while (true)
{
Console.WriteLine("无限循环");
}
那么,对应的 Loop 重载是这种
public static LoopExpression Loop(Expression body)
使用表达式树编写
BlockExpression _block = Expression.Block(
new ParameterExpression[] { },
Expression.Call(null, typeof(Console).GetMethod("WriteLine", new Type[] { typeof(string) }),Expression.Constant("无限循环") )
);
LoopExpression _loop = Expression.Loop(_block);
Expression<Action> lambda = Expression.Lambda<Action>(_loop);
lambda.Compile()();
最简单的循环
如果我想用表达式树做到如下最简单的循环,怎么写?
while (true)
{
Console.WriteLine("我被执行一次就结束循环了");
break;
}
表达式树编写
LabelTarget _break = Expression.Label();
BlockExpression _block = Expression.Block(
new ParameterExpression[] { },
Expression.Call(null, typeof(Console).GetMethod("WriteLine", new Type[] { typeof(string) }), Expression.Constant("我被执行一次就结束循环了")), Expression.Break(_break));
LoopExpression _loop = Expression.Loop(_block, _break);
Expression<Action> lambda = Expression.Lambda<Action>(_loop);
lambda.Compile()();
Console.ReadKey();
生成的表达式树
.Lambda #Lambda1<System.Action>() {
.Loop {
.Block() {
.Call System.Console.WriteLine("我被执行一次就结束循环了");
.Break #Label1 { }
}
}
.LabelTarget #Label1:
}
首先要明确,Expression.Label()
里面可以为空,它是一种标记,不参与传递参数,不参与运算。有参无参,前后保持一致即可。
但是上面的循环只有一次,你可以将上面的标签改成这样试试 LabelTarget _break = Expression.Label(typeof(int));
,原因后面找。
还有, Expression.Label() 变量需要一致,否则无法跳出。
试试一下代码
BlockExpression _block = Expression.Block(