C#循環(huán)與循環(huán)控制的表達(dá)式樹實(shí)現(xiàn)
C# 提供了以下幾種循環(huán)類型。
| 循環(huán)類型 | 描述 |
|---|---|
| while 循環(huán) | 當(dāng)給定條件為真時(shí),重復(fù)語句或語句組。它會(huì)在執(zhí)行循環(huán)主體之前測試條件。 |
| for/foreach 循環(huán) | 多次執(zhí)行一個(gè)語句序列,簡化管理循環(huán)變量的代碼。 |
| do...while 循環(huán) | 除了它是在循環(huán)主體結(jié)尾測試條件外,其他與 while 語句類似。 |
| 嵌套循環(huán) | 您可以在 while、for 或 do..while 循環(huán)內(nèi)使用一個(gè)或多個(gè)循環(huán)。 |
當(dāng)然,還有以下用于控制循環(huán)的語句
| 控制語句 | 描述 |
|---|---|
| break 語句 | 終止 loop 或 switch 語句,程序流將繼續(xù)執(zhí)行緊接著 loop 或 switch 的下一條語句。 |
| continue 語句 | 引起循環(huán)跳過主體的剩余部分,立即重新開始測試條件。 |
LabelTarget
LabelTarget 是用于創(chuàng)建循環(huán)標(biāo)記的。
無論是 for 還是 while ,平時(shí)編寫循環(huán)時(shí),都需要有跳出循環(huán)的判斷,有時(shí)需要某個(gè)參數(shù)自增自減并且作為判斷依據(jù)。
C# 表達(dá)式樹里面是沒有專門表示 for /while 的,里面只有一個(gè) Loop??匆幌翷oop 生成的表達(dá)式樹
.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,不然就無限循環(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á)式樹里面的循環(huán),只有 Loop,無 for / while 的區(qū)別。
那么,我們來一步步理解 Loop 循環(huán)和 LabelTarget;
無限循環(huán)
while (true)
{
Console.WriteLine("無限循環(huán)");
}那么,對(duì)應(yīng)的 Loop 重載是這種
public static LoopExpression Loop(Expression body)
使用表達(dá)式樹編寫
BlockExpression _block = Expression.Block(
new ParameterExpression[] { },
Expression.Call(null, typeof(Console).GetMethod("WriteLine", new Type[] { typeof(string) }),Expression.Constant("無限循環(huán)") )
);
LoopExpression _loop = Expression.Loop(_block);
Expression<Action> lambda = Expression.Lambda<Action>(_loop);
lambda.Compile()();最簡單的循環(huán)
如果我想用表達(dá)式樹做到如下最簡單的循環(huán),怎么寫?
while (true)
{
Console.WriteLine("我被執(zhí)行一次就結(jié)束循環(huán)了");
break;
}表達(dá)式樹編寫
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á)式樹
.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)算。有參無參,前后保持一致即可。
但是上面的循環(huán)只有一次,你可以將上面的標(biāo)簽改成這樣試試 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("我被執(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á)式樹里面不是完全按照 C# 的語法來還原操作的。
對(duì)于 Block() 的使用,多加實(shí)踐即可。
多次循環(huán)
寫一個(gè)循環(huán)十次的循環(huán)語句
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á)式樹編寫
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á)式樹如下
.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(有參或無參);,Expression.Break(_break, a) 與 Expression.Break(_break),只要看看最終生成的表達(dá)式樹就清楚了。
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á)式樹編寫(筆者將步驟詳細(xì)拆分了,所以代碼比較長)
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á)式樹如下
.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:
}為了便于理解,上面的代碼拆分了很多步。
來個(gè)簡化版本
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 )
以上就是本文的全部內(nèi)容,希望對(duì)大家的學(xué)習(xí)有所幫助,也希望大家多多支持腳本之家。
- C#表達(dá)式樹基礎(chǔ)教程
- C#判斷語句的表達(dá)式樹實(shí)現(xiàn)
- C#五類運(yùn)算符使用表達(dá)式樹進(jìn)行操作
- C#使用表達(dá)式樹(LambdaExpression)動(dòng)態(tài)更新類的屬性值(示例代碼)
- C#表達(dá)式樹講解
- C#使用表達(dá)式樹實(shí)現(xiàn)對(duì)象復(fù)制的示例代碼
- C#表達(dá)式樹Expression基礎(chǔ)講解
- C# Lambda表達(dá)式及Lambda表達(dá)式樹的創(chuàng)建過程
- C#用表達(dá)式樹構(gòu)建動(dòng)態(tài)查詢的方法
- C#表達(dá)式樹的基本用法講解
- 淺談c#表達(dá)式樹Expression簡單類型比較demo
- C# 表達(dá)式樹Expression Trees的知識(shí)梳理
- C#之Expression表達(dá)式樹實(shí)例
- C#值類型、引用類型、泛型、集合、調(diào)用函數(shù)的表達(dá)式樹實(shí)踐
相關(guān)文章
C#設(shè)置WinForm中DataGrid列的方法(列寬/列標(biāo)題等)
這篇文章主要介紹了C#設(shè)置WinForm中DataGrid列的方法,包括列寬、列標(biāo)題等部分,并分析了其中相關(guān)的操作技巧,具有一定參考借鑒價(jià)值,需要的朋友可以參考下2015-07-07
C#連接SQLite數(shù)據(jù)庫并實(shí)現(xiàn)基本操作
本文介紹了SQLite,一個(gè)輕量級(jí)的跨平臺(tái)數(shù)據(jù)庫管理系統(tǒng),以及如何在C#中使用System.Data.SQLite庫進(jìn)行操作,包括創(chuàng)建、修改和查詢數(shù)據(jù)庫,以及使用SQLiteHelper類簡化SQL使用,此外,還提到了DB文件查看工具SQLiteSpy的應(yīng)用,需要的朋友可以參考下2024-12-12
C#設(shè)計(jì)模式之建造者模式生成器模式示例詳解
這篇文章主要為大家介紹了C#設(shè)計(jì)模式之建造者模式生成器模式示例詳解,有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進(jìn)步,早日升職加薪2022-08-08
WPF實(shí)現(xiàn)繪制統(tǒng)計(jì)圖(柱狀圖)的方法詳解
這篇文章主要為大家詳細(xì)介紹了如何基于WPF實(shí)現(xiàn)實(shí)現(xiàn)統(tǒng)計(jì)圖(柱狀圖)的繪制,文中的示例代碼簡潔易懂,對(duì)我們學(xué)習(xí)WPF有一定幫助,感興趣的可以了解一下2022-07-07
C#將配置文件appsetting中的值轉(zhuǎn)換為動(dòng)態(tài)對(duì)象調(diào)用
這篇文章主要介紹了將配置文件appsetting中的值轉(zhuǎn)換為動(dòng)態(tài)對(duì)象調(diào)用 ,非常不錯(cuò),具有一定的參考借鑒價(jià)值,需要的朋友可以參考下2018-09-09

