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() { .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); expressionlambda = expression.lambda (_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); expressionlambda = expression.lambda (_loop); lambda.compile()(); console.readkey();
生成的表达式树
.lambda #lambda1() { .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()); expressionlambda = expression.lambda (_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> lambda = expression.lambda >(_loop, a); lambda.compile()(0); console.readkey();
生成的表达式树如下
.lambda #lambda1(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> lambda = expression.lambda >(loop, a); lambda.compile()(0); console.readkey();
生成的表达式树如下
.lambda #lambda1(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> lambda = expression.lambda >(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 )
以上就是本文的全部内容,希望对大家的学习有所帮助,也希望大家多多支持。