目录
 * 表达式树练习实践:C# 循环 
<https://www.cnblogs.com/whuanle/p/11559795.html#表达式树练习实践c-循环> 
 * LabelTarget <https://www.cnblogs.com/whuanle/p/11559795.html#labeltarget> 
 * for / while 循环 
<https://www.cnblogs.com/whuanle/p/11559795.html#for-while-循环> 
 * 无限循环 <https://www.cnblogs.com/whuanle/p/11559795.html#无限循环> 
 * 最简单的循环 <https://www.cnblogs.com/whuanle/p/11559795.html#最简单的循环> 
 * 多次循环 <https://www.cnblogs.com/whuanle/p/11559795.html#多次循环> 
 * break 和 continue 一起 
<https://www.cnblogs.com/whuanle/p/11559795.html#break-和-continue-一起> 
表达式树练习实践: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( new ParameterExpression[] { }, 
Expression.Call(null, typeof(Console).GetMethod("WriteLine", new Type[] { 
typeof(string) }), Expression.Constant("我被执行一次就结束循环了")), 
Expression.Break(Expression.Label())); LoopExpression _loop = 
Expression.Loop(_block, Expression.Label()); Expression<Action> lambda = 
Expression.Lambda<Action>(_loop); lambda.Compile()(); Console.ReadKey(); 
里面用到了 Expression.Block(),Block() 是块,即{}。
如果 Block() 是在最外层,那么相当于是函数;如果是内嵌,相当于{};
但不是真的这样。。。表达式树里面不是完全按照 C# 的语法来还原操作的。
对于 Block() 的使用,多加实践即可。
多次循环
写一个循环十次的循环语句
 for (int i = 0; i < 10; i++) { if (i < 10) { Console.WriteLine(i); } else 
break; } 
或者使用 while 表示
 int i = 0; while (true) { if (i < 10) { Console.WriteLine(i); } else break; 
i++; } 
使用表达式树编写
 LabelTarget _break = Expression.Label(typeof(int)); ParameterExpression a = 
Expression.Variable(typeof(int), "a"); BlockExpression _block = 
Expression.Block(new ParameterExpression[] { }, Expression.IfThenElse ( 
Expression.LessThan(a, Expression.Constant(10)), Expression.Call(null, 
typeof(Console).GetMethod("WriteLine", new Type[] { typeof(int) }), a), 
Expression.Break(_break, a) ), Expression.PostIncrementAssign(a) // a++ ); 
LoopExpression _loop = Expression.Loop(_block, _break); Expression<Action<int>> 
lambda = Expression.Lambda<Action<int>>(_loop, a); lambda.Compile()(0); 
Console.ReadKey(); 
生成的表达式树如下
.Lambda #Lambda1<System.Action`1[System.Int32]>(System.Int32 $a) { .Loop { 
.Block() { .If ($a < 10) { .Call System.Console.WriteLine($a) } .Else { .Break 
#Label1 { $a } }; $a++ } } .LabelTarget #Label1: } 
试试将 Expression.Break(_break, a) 改成 Expression.Break(_break)。看看报什么错。。。
解决方法是,上面的标记也改成 LabelTarget _break = Expression.Label();。
就跟你写代码写注释一样,里面的东西是为了让别人看代码是容易理解。
有些同学纠结于 Expression.Label(有参或无参);,Expression.Break(_break, a) 与 
Expression.Break(_break),只要看看最终生成的表达式树就清楚了。
break 和 continue 一起
C# 循环代码如下
 int i = 0; while (true) { if (i < 10) { if (i % 2 == 0) { 
Console.Write("i是偶数:"); Console.WriteLine(i); i++; continue; } 
Console.WriteLine("其他任务 --"); Console.WriteLine("其他任务 --"); } else break; i++; }
使用 C# 表达式树编写(笔者将步骤详细拆分了,所以代码比较长)
 ParameterExpression a = Expression.Variable(typeof(int), "a"); LabelTarget 
_break = Expression.Label(); LabelTarget _continue = Expression.Label(); // if 
(i % 2 == 0) // { // Console.Write("i是偶数:"); // Console.WriteLine(i); // i++; 
// continue; // } ConditionalExpression _if = Expression.IfThen( 
Expression.Equal(Expression.Modulo(a, Expression.Constant(2)), 
Expression.Constant(0)), Expression.Block( new ParameterExpression[] { }, 
Expression.Call(null, typeof(Console).GetMethod("Write", new Type[] { 
typeof(string) }), Expression.Constant("i是偶数:")), Expression.Call(null, 
typeof(Console).GetMethod("WriteLine", new Type[] { typeof(int) }), a), 
Expression.PostIncrementAssign(a), Expression.Continue(_continue) ) ); // if (i 
% 2 == 0) // { // Console.Write("i是偶数:"); // Console.WriteLine(i); // i++; // 
continue; // } // Console.WriteLine("其他任务 --"); // Console.WriteLine("其他任务 
--"); BlockExpression block1 = Expression.Block( new ParameterExpression[] { }, 
_if, Expression.Call(null, typeof(Console).GetMethod("WriteLine", new Type[] { 
typeof(string) }), Expression.Constant("其他任务 --")), Expression.Call(null, 
typeof(Console).GetMethod("WriteLine", new Type[] { typeof(string) }), 
Expression.Constant("其他任务 --")) ); // if (i < 10) // { // if (i % 2 == 0) // { 
// Console.Write("i是偶数:"); // Console.WriteLine(i); // i++; // continue; // } 
// Console.WriteLine("其他任务 --"); // Console.WriteLine("其他任务 --"); // } // else 
break; ConditionalExpression if_else = Expression.IfThenElse( 
Expression.LessThan(a, Expression.Constant(10)), block1, 
Expression.Break(_break) ); // if (i < 10) // { // if (i % 2 == 0) // { // 
Console.Write("i是偶数:"); // Console.WriteLine(i); // i++; // continue; // } // 
Console.WriteLine("其他任务 --"); // Console.WriteLine("其他任务 --"); // } // else 
break; // i++ ; BlockExpression block2 = Expression.Block( new 
ParameterExpression[] { }, if_else, Expression.PostIncrementAssign(a) ); // 
while(true) LoopExpression loop = Expression.Loop(block2, _break, _continue); 
Expression<Action<int>> lambda = Expression.Lambda<Action<int>>(loop, a); 
lambda.Compile()(0); Console.ReadKey(); 
生成的表达式树如下
.Lambda #Lambda1<System.Action`1[System.Int32]>(System.Int32 $a) { .Loop 
.LabelTarget #Label1: { .Block() { .If ($a < 10) { .Block() { .If ( $a % 2 == 0 
) { .Block() { .Call System.Console.Write("i是偶数:"); .Call 
System.Console.WriteLine($a); $a++; .Continue #Label1 { } } } .Else { 
.Default(System.Void) }; .Call System.Console.WriteLine("其他任务 --"); .Call 
System.Console.WriteLine("其他任务 --") } } .Else { .Break #Label2 { } }; $a++ } } 
.LabelTarget #Label2: } 
为了便于理解,上面的代码拆分了很多步。
来个简化版本
 ParameterExpression a = Expression.Variable(typeof(int), "a"); LabelTarget 
_break = Expression.Label(); LabelTarget _continue = Expression.Label(); 
LoopExpression loop = Expression.Loop( Expression.Block( new 
ParameterExpression[] { }, Expression.IfThenElse( Expression.LessThan(a, 
Expression.Constant(10)), Expression.Block( new ParameterExpression[] { }, 
Expression.IfThen( Expression.Equal(Expression.Modulo(a, 
Expression.Constant(2)), Expression.Constant(0)), Expression.Block( new 
ParameterExpression[] { }, Expression.Call(null, 
typeof(Console).GetMethod("Write", new Type[] { typeof(string) }), 
Expression.Constant("i是偶数:")), Expression.Call(null, 
typeof(Console).GetMethod("WriteLine", new Type[] { typeof(int) }), a), 
Expression.PostIncrementAssign(a), Expression.Continue(_continue) ) ), 
Expression.Call(null, typeof(Console).GetMethod("WriteLine", new Type[] { 
typeof(string) }), Expression.Constant("其他任务 --")), Expression.Call(null, 
typeof(Console).GetMethod("WriteLine", new Type[] { typeof(string) }), 
Expression.Constant("其他任务 --")) ), Expression.Break(_break) ), 
Expression.PostIncrementAssign(a) ), _break, _continue ); 
Expression<Action<int>> lambda = Expression.Lambda<Action<int>>(loop, a); 
lambda.Compile()(0); Console.ReadKey(); 
需要注意的是,Expression.Break Expression.Continue 有所区别。
当标签实例化都是 Expression.Label() 时,
Expression.Break(label); Expression.Continu(label); 
区别在于 continu 只能用 Expression.Label()。
Break 可以这样
LabelTarget label = Expression.Label ( typeof ( int ) ); ParameterExpression a 
= Expression.Variable(typeof(int), "a"); Expression.Break ( label , a ) 
热门工具 换一换