欧美bbbwbbbw肥妇,免费乱码人妻系列日韩,一级黄片

C#循環(huán)與循環(huán)控制的表達(dá)式樹(shù)實(shí)現(xiàn)

 更新時(shí)間:2022年01月18日 10:38:10   作者:癡者工良  
這篇文章介紹了C#循環(huán)與循環(huán)控制的表達(dá)式樹(shù)實(shí)現(xiàn),文中通過(guò)示例代碼介紹的非常詳細(xì)。對(duì)大家的學(xué)習(xí)或工作具有一定的參考借鑒價(jià)值,需要的朋友可以參考下

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í)有所幫助,也希望大家多多支持腳本之家。

相關(guān)文章

最新評(píng)論