網站首頁 編程語言 正文
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??匆幌翷oop 生成的表達式樹
.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 )
原文鏈接:https://www.cnblogs.com/whuanle/p/11559795.html
相關推薦
- 2023-08-28 react:使用 moment 來獲取日期
- 2022-12-19 C++?Boost?Fusion創建異構容器詳解_C 語言
- 2022-08-10 Python接口自動化之request請求封裝源碼分析_python
- 2022-06-17 Redis實現驗證碼發送并限制每日發送次數的示例代碼_Redis
- 2022-04-18 http通過StreamingHttpResponse完成連續的數據傳輸長鏈接方式_python
- 2022-07-03 關于python中range()的參數問題_python
- 2023-01-19 Oracle查詢表空間大小及每個表所占空間的大小語句示例_oracle
- 2022-07-23 Python實現環形鏈表_python
- 最近更新
-
- window11 系統安裝 yarn
- 超詳細win安裝深度學習環境2025年最新版(
- Linux 中運行的top命令 怎么退出?
- MySQL 中decimal 的用法? 存儲小
- get 、set 、toString 方法的使
- @Resource和 @Autowired注解
- Java基礎操作-- 運算符,流程控制 Flo
- 1. Int 和Integer 的區別,Jav
- spring @retryable不生效的一種
- Spring Security之認證信息的處理
- Spring Security之認證過濾器
- Spring Security概述快速入門
- Spring Security之配置體系
- 【SpringBoot】SpringCache
- Spring Security之基于方法配置權
- redisson分布式鎖中waittime的設
- maven:解決release錯誤:Artif
- restTemplate使用總結
- Spring Security之安全異常處理
- MybatisPlus優雅實現加密?
- Spring ioc容器與Bean的生命周期。
- 【探索SpringCloud】服務發現-Nac
- Spring Security之基于HttpR
- Redis 底層數據結構-簡單動態字符串(SD
- arthas操作spring被代理目標對象命令
- Spring中的單例模式應用詳解
- 聊聊消息隊列,發送消息的4種方式
- bootspring第三方資源配置管理
- GIT同步修改后的遠程分支