表达式树练习实践:C# 循环与循环控制

表达式树练习实践:C# 循环与循环控制,第1张

概述表达式树练习实践:C 循环 [TOC] C 提供了以下几种循环类型。 | 循环类型 | 描述 | | : | : | | while 循环 | 当给定条件为真时,重复语句或语句组。它会在执行循环主体之 表达式树练习实践:C# 循环

目录表达式树练习实践:C# 循环LabelTargetfor / while 循环无限循环最简单的循环多次循环break 和 continue 一起

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<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.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.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)),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[] { },typeof(Console).getmethod("Write",Expression.Constant("i是偶数:")),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.Constant("其他任务 --")),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,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.Block(                            new ParameterExpression[] { },Expression.IfThen(                                Expression.Equal(Expression.Modulo(a,Expression.Block(                                    new ParameterExpression[] { },Expression.Continue(_continue)                                    )                                ),Expression.Constant("其他任务 --"))                            ),Expression.Break(_break)                        ),Expression.PostIncrementAssign(a)                    ),_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 ) 
总结

以上是内存溢出为你收集整理的表达式树练习实践:C# 循环与循环控制全部内容,希望文章能够帮你解决表达式树练习实践:C# 循环与循环控制所遇到的程序开发问题。

如果觉得内存溢出网站内容还不错,欢迎将内存溢出网站推荐给程序员好友。

欢迎分享,转载请注明来源:内存溢出

原文地址: http://outofmemory.cn/langs/1213948.html

(0)
打赏 微信扫一扫 微信扫一扫 支付宝扫一扫 支付宝扫一扫
上一篇 2022-06-04
下一篇 2022-06-04

发表评论

登录后才能评论

评论列表(0条)

保存