C#循環(huán)與循環(huán)控制的表達(dá)式樹(shù)實(shí)現(xiàn)
C# 提供了以下幾種循環(huán)類型。
循環(huán)類型 | 描述 |
---|---|
while 循環(huán) | 當(dāng)給定條件為真時(shí),重復(fù)語(yǔ)句或語(yǔ)句組。它會(huì)在執(zhí)行循環(huán)主體之前測(cè)試條件。 |
for/foreach 循環(huán) | 多次執(zhí)行一個(gè)語(yǔ)句序列,簡(jiǎn)化管理循環(huán)變量的代碼。 |
do...while 循環(huán) | 除了它是在循環(huán)主體結(jié)尾測(cè)試條件外,其他與 while 語(yǔ)句類似。 |
嵌套循環(huán) | 您可以在 while、for 或 do..while 循環(huán)內(nèi)使用一個(gè)或多個(gè)循環(huán)。 |
當(dāng)然,還有以下用于控制循環(huán)的語(yǔ)句
控制語(yǔ)句 | 描述 |
---|---|
break 語(yǔ)句 | 終止 loop 或 switch 語(yǔ)句,程序流將繼續(xù)執(zhí)行緊接著 loop 或 switch 的下一條語(yǔ)句。 |
continue 語(yǔ)句 | 引起循環(huán)跳過(guò)主體的剩余部分,立即重新開(kāi)始測(cè)試條件。 |
LabelTarget
LabelTarget 是用于創(chuàng)建循環(huán)標(biāo)記的。
無(wú)論是 for 還是 while ,平時(shí)編寫循環(huán)時(shí),都需要有跳出循環(huán)的判斷,有時(shí)需要某個(gè)參數(shù)自增自減并且作為判斷依據(jù)。
C# 表達(dá)式樹(shù)里面是沒(méi)有專門表示 for /while 的,里面只有一個(gè) Loop??匆幌翷oop 生成的表達(dá)式樹(shù)
.Lambda #Lambda1<System.Func`1[System.Int32]>() { .Block(System.Int32 $x) { $x = 0; .Loop { .If ($x < 10) { $x++ } .Else { .Break #Label1 { $x } } } .LabelTarget #Label1: } }
要實(shí)現(xiàn)循環(huán)控制,有 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);
所以,要實(shí)現(xiàn)循環(huán)控制,必須要使用 LabelTarget,不然就無(wú)限循環(huán)了。
要理解 LabelTarget ,最好的方法是動(dòng)手做。
for / while 循環(huán)
Expression.Loop 用于創(chuàng)建循環(huán),包括 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);
表達(dá)式樹(shù)里面的循環(huán),只有 Loop,無(wú) for / while 的區(qū)別。
那么,我們來(lái)一步步理解 Loop 循環(huán)和 LabelTarget;
無(wú)限循環(huán)
while (true) { Console.WriteLine("無(wú)限循環(huán)"); }
那么,對(duì)應(yīng)的 Loop 重載是這種
public static LoopExpression Loop(Expression body)
使用表達(dá)式樹(shù)編寫
BlockExpression _block = Expression.Block( new ParameterExpression[] { }, Expression.Call(null, typeof(Console).GetMethod("WriteLine", new Type[] { typeof(string) }),Expression.Constant("無(wú)限循環(huán)") ) ); LoopExpression _loop = Expression.Loop(_block); Expression<Action> lambda = Expression.Lambda<Action>(_loop); lambda.Compile()();
最簡(jiǎn)單的循環(huán)
如果我想用表達(dá)式樹(shù)做到如下最簡(jiǎn)單的循環(huán),怎么寫?
while (true) { Console.WriteLine("我被執(zhí)行一次就結(jié)束循環(huán)了"); break; }
表達(dá)式樹(shù)編寫
LabelTarget _break = Expression.Label(); BlockExpression _block = Expression.Block( new ParameterExpression[] { }, Expression.Call(null, typeof(Console).GetMethod("WriteLine", new Type[] { typeof(string) }), Expression.Constant("我被執(zhí)行一次就結(jié)束循環(huán)了")), Expression.Break(_break)); LoopExpression _loop = Expression.Loop(_block, _break); Expression<Action> lambda = Expression.Lambda<Action>(_loop); lambda.Compile()(); Console.ReadKey();
生成的表達(dá)式樹(shù)
.Lambda #Lambda1<System.Action>() { .Loop { .Block() { .Call System.Console.WriteLine("我被執(zhí)行一次就結(jié)束循環(huán)了"); .Break #Label1 { } } } .LabelTarget #Label1: }
首先要明確,Expression.Label()
里面可以為空,它是一種標(biāo)記,不參與傳遞參數(shù),不參與運(yùn)算。有參無(wú)參,前后保持一致即可。
但是上面的循環(huán)只有一次,你可以將上面的標(biāo)簽改成這樣試試 LabelTarget _break = Expression.Label(typeof(int));
,原因后面找。
還有, Expression.Label() 變量需要一致,否則無(wú)法跳出。
試試一下代碼
BlockExpression _block = Expression.Block( new ParameterExpression[] { }, Expression.Call(null, typeof(Console).GetMethod("WriteLine", new Type[] { typeof(string) }), Expression.Constant("我被執(zhí)行一次就結(jié)束循環(huán)了")), 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() 是在最外層,那么相當(dāng)于是函數(shù);如果是內(nèi)嵌,相當(dāng)于{};
但不是真的這樣。。。表達(dá)式樹(shù)里面不是完全按照 C# 的語(yǔ)法來(lái)還原操作的。
對(duì)于 Block() 的使用,多加實(shí)踐即可。
多次循環(huán)
寫一個(gè)循環(huán)十次的循環(huán)語(yǔ)句
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++; }
使用表達(dá)式樹(shù)編寫
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();
生成的表達(dá)式樹(shù)如下
.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)
??纯磮?bào)什么錯(cuò)。。。
解決方法是,上面的標(biāo)記也改成 LabelTarget _break = Expression.Label();
。
就跟你寫代碼寫注釋一樣,里面的東西是為了讓別人看代碼是容易理解。
有些同學(xué)糾結(jié)于 Expression.Label(有參或無(wú)參);
,Expression.Break(_break, a)
與 Expression.Break(_break)
,只要看看最終生成的表達(dá)式樹(shù)就清楚了。
break 和 continue 一起
C# 循環(huán)代碼如下
int i = 0; while (true) { if (i < 10) { if (i % 2 == 0) { Console.Write("i是偶數(shù):"); Console.WriteLine(i); i++; continue; } Console.WriteLine("其他任務(wù) --"); Console.WriteLine("其他任務(wù) --"); } else break; i++; }
使用 C# 表達(dá)式樹(shù)編寫(筆者將步驟詳細(xì)拆分了,所以代碼比較長(zhǎng))
ParameterExpression a = Expression.Variable(typeof(int), "a"); LabelTarget _break = Expression.Label(); LabelTarget _continue = Expression.Label(); // if (i % 2 == 0) // { // Console.Write("i是偶數(shù):"); // 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是偶數(shù):")), 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是偶數(shù):"); // Console.WriteLine(i); // i++; // continue; // } // Console.WriteLine("其他任務(wù) --"); // Console.WriteLine("其他任務(wù) --"); BlockExpression block1 = Expression.Block( new ParameterExpression[] { }, _if, Expression.Call(null, typeof(Console).GetMethod("WriteLine", new Type[] { typeof(string) }), Expression.Constant("其他任務(wù) --")), Expression.Call(null, typeof(Console).GetMethod("WriteLine", new Type[] { typeof(string) }), Expression.Constant("其他任務(wù) --")) ); // if (i < 10) // { // if (i % 2 == 0) // { // Console.Write("i是偶數(shù):"); // Console.WriteLine(i); // i++; // continue; // } // Console.WriteLine("其他任務(wù) --"); // Console.WriteLine("其他任務(wù) --"); // } // 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是偶數(shù):"); // Console.WriteLine(i); // i++; // continue; // } // Console.WriteLine("其他任務(wù) --"); // Console.WriteLine("其他任務(wù) --"); // } // 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();
生成的表達(dá)式樹(shù)如下
.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是偶數(shù):"); .Call System.Console.WriteLine($a); $a++; .Continue #Label1 { } } } .Else { .Default(System.Void) }; .Call System.Console.WriteLine("其他任務(wù) --"); .Call System.Console.WriteLine("其他任務(wù) --") } } .Else { .Break #Label2 { } }; $a++ } } .LabelTarget #Label2: }
為了便于理解,上面的代碼拆分了很多步。
來(lái)個(gè)簡(jiǎn)化版本
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是偶數(shù):")), 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("其他任務(wù) --")), Expression.Call(null, typeof(Console).GetMethod("WriteLine", new Type[] { typeof(string) }), Expression.Constant("其他任務(wù) --")) ), 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
有所區(qū)別。
當(dāng)標(biāo)簽實(shí)例化都是 Expression.Label()
時(shí),
Expression.Break(label); Expression.Continu(label);
區(qū)別在于 continu 只能用 Expression.Label()。
Break 可以這樣
LabelTarget label = Expression.Label ( typeof ( int ) ); ParameterExpression a = Expression.Variable(typeof(int), "a"); Expression.Break ( label , a )
以上就是本文的全部?jī)?nèi)容,希望對(duì)大家的學(xué)習(xí)有所幫助,也希望大家多多支持腳本之家。
- C#表達(dá)式樹(shù)基礎(chǔ)教程
- C#判斷語(yǔ)句的表達(dá)式樹(shù)實(shí)現(xiàn)
- C#五類運(yùn)算符使用表達(dá)式樹(shù)進(jìn)行操作
- C#使用表達(dá)式樹(shù)(LambdaExpression)動(dòng)態(tài)更新類的屬性值(示例代碼)
- C#表達(dá)式樹(shù)講解
- C#使用表達(dá)式樹(shù)實(shí)現(xiàn)對(duì)象復(fù)制的示例代碼
- C#表達(dá)式樹(shù)Expression基礎(chǔ)講解
- C# Lambda表達(dá)式及Lambda表達(dá)式樹(shù)的創(chuàng)建過(guò)程
- C#用表達(dá)式樹(shù)構(gòu)建動(dòng)態(tài)查詢的方法
- C#表達(dá)式樹(shù)的基本用法講解
- 淺談c#表達(dá)式樹(shù)Expression簡(jiǎn)單類型比較demo
- C# 表達(dá)式樹(shù)Expression Trees的知識(shí)梳理
- C#之Expression表達(dá)式樹(shù)實(shí)例
- C#值類型、引用類型、泛型、集合、調(diào)用函數(shù)的表達(dá)式樹(shù)實(shí)踐
相關(guān)文章
C#實(shí)現(xiàn)遠(yuǎn)程關(guān)閉計(jì)算機(jī)或重啟計(jì)算機(jī)的方法
這篇文章主要介紹了C#實(shí)現(xiàn)遠(yuǎn)程關(guān)閉計(jì)算機(jī)或重啟計(jì)算機(jī)的方法,涉及C#遠(yuǎn)程連接及系統(tǒng)命令的調(diào)用技巧,具有一定參考借鑒價(jià)值,需要的朋友可以參考下2015-08-08c#的時(shí)間日期操作示例分享(c#獲取當(dāng)前日期)
這篇文章主要介紹了c#的時(shí)間日期操作示例,在給定時(shí)間戳返回指定的時(shí)間格式和獲取當(dāng)前時(shí)間方法,需要的朋友可以參考下2014-03-03深入學(xué)習(xí)C#網(wǎng)絡(luò)編程之HTTP應(yīng)用編程(下)
這篇文章主要介紹了深入學(xué)習(xí)C#網(wǎng)絡(luò)編程之HTTP應(yīng)用編程的相關(guān)知識(shí),文中講解的非常詳細(xì),幫助大家更好的學(xué)習(xí)c#網(wǎng)絡(luò)編程,感興趣的朋友可以了解下2020-06-06C#實(shí)現(xiàn)簡(jiǎn)單學(xué)生成績(jī)管理系統(tǒng)
這篇文章主要為大家詳細(xì)介紹了C#實(shí)現(xiàn)簡(jiǎn)單學(xué)生成績(jī)管理系統(tǒng),文中示例代碼介紹的非常詳細(xì),具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下2022-08-08C# 實(shí)現(xiàn)Scoket心跳機(jī)制的方法
這篇文章主要介紹了C# 實(shí)現(xiàn)Scoket心跳機(jī)制的方法,文中通過(guò)示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來(lái)一起學(xué)習(xí)學(xué)習(xí)吧2020-02-02如何在Mac系統(tǒng)使用Visual Studio Code運(yùn)行Python
這篇文章主要介紹了Mac使用Visual Studio Code運(yùn)行Python環(huán)境的方法,本文通過(guò)圖文并茂的形式給大家介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或工作具有一定的參考借鑒價(jià)值,需要的朋友可以參考下2020-04-04Winform開(kāi)發(fā)中使用下拉列表展示字典數(shù)據(jù)的幾種方式
這篇文章介紹了Winform開(kāi)發(fā)中使用下拉列表展示字典數(shù)據(jù)的幾種方式,文中通過(guò)示例代碼介紹的非常詳細(xì)。對(duì)大家的學(xué)習(xí)或工作具有一定的參考借鑒價(jià)值,需要的朋友可以參考下2022-09-09C#使用密封類實(shí)現(xiàn)密封用戶信息的示例詳解
在C#中,密封類(sealed class)是一種不能被其他類繼承的類,它用于防止其他類繼承它的功能和屬性, 下面我們就來(lái)看看如何使用密封類密封用戶的信息吧2024-02-02