Warning: file_get_contents(/data/phpspider/zhask/data//catemap/9/loops/2.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
C# 去做与去做的区别_C#_Loops_Do While_Goto - Fatal编程技术网

C# 去做与去做的区别

C# 去做与去做的区别,c#,loops,do-while,goto,C#,Loops,Do While,Goto,以下两个C#代码段在执行上有什么不同 do { Console.WriteLine(x.ToString()); ++x; } while (x < 7); do { Console.WriteLine(x.ToString()); ++x; } x

以下两个C#代码段在执行上有什么不同

do
{
    Console.WriteLine(x.ToString());
    ++x;
} 
while (x < 7);
do
{
Console.WriteLine(x.ToString());
++x;
} 
x<7;

标签:
{
Console.WriteLine(x.ToString());
++x;
}
如果(x<7)goto标签;
我想弄明白为什么goto这么糟糕。 谢谢

编辑:如果我添加括号,代码片段非常相似。

EDIT2:在VisualStudio中,我单击了“转到反汇编”,得到了以下代码:

            do
            {
00000037  nop 
                Console.WriteLine(x.ToString());
00000038  lea         ecx,[ebp-40h] 
0000003b  call        63129C98 
00000040  mov         dword ptr [ebp-48h],eax 
00000043  mov         ecx,dword ptr [ebp-48h] 
00000046  call        63148168 
0000004b  nop 
                ++x;
0000004c  inc         dword ptr [ebp-40h] 
            } 
0000004f  nop 
            while (x < 7);
00000050  cmp         dword ptr [ebp-40h],7 
00000054  setl        al 
00000057  movzx       eax,al 
0000005a  mov         dword ptr [ebp-44h],eax 
0000005d  cmp         dword ptr [ebp-44h],0 
00000061  jne         00000037 
do
{
00000037无
Console.WriteLine(x.ToString());
000000 38 lea ecx,[ebp-40h]
000000 3B呼叫63129C98
000000 40 mov德沃德ptr[ebp-48h],eax
000000 43 mov ecx,德沃德ptr[ebp-48h]
00000046致电63148168
0000004b无
++x;
0000004c公司dword ptr[ebp-40h]
} 
0000004f无
x<7;
00000050 cmp dword ptr[ebp-40h],7
00000054 setl al
000000 57 movzx eax,al
000000 5A mov dword ptr[ebp-44h],eax
000000 5D cmp dword ptr[ebp-44h],0
00000061 jne 00000037

标签:
{
Console.WriteLine(x.ToString());
000000 69 lea ecx,[ebp-40h]
0000006c呼叫63129C98
000000 71 mov德沃德ptr[ebp-4Ch],eax
000000 74 mov ecx,德沃德ptr[ebp-4Ch]
00000077呼叫63148168
0000007c无
++x;
000000 7D公司dword ptr[ebp-40h]
}
00000080无
如果(x<7)goto标签;
000000 81 cmp dword ptr[ebp-40h],7
000000 85塞奇艾尔
000000 88 movzx eax,al
000000 8B mov dword ptr[ebp-44h],eax
000000 8E cmp dword ptr[ebp-44h],0
00000092 jne 00000097
00000094无
000000 95 jmp 000000 68

区别在于无条件跳转。

不,我甚至认为
是像后面那样实现的

使用
goto
的不好之处在于,它鼓励在代码中来回移动(也被称为“意大利面代码”:这是一团乱)。它使您的代码极难阅读、调试和分析,并引入了bug,因为您无法真正理解正在发生的事情


while
的好处在于,您可以理解它,编译器也可以理解它,因此它可以为您提供很好的警告。

让我们看看IL:

.method private hidebysig 
    instance void While () cil managed 
{
    // Method begins at RVA 0x2050
    // Code size 31 (0x1f)
    .maxstack 2
    .locals init (
        [0] int32 x,
        [1] bool CS$4$0000
    )

    IL_0000: nop
    IL_0001: ldc.i4.0
    IL_0002: stloc.0
    // loop start (head: IL_0003)
        IL_0003: nop
        IL_0004: ldloca.s x
        IL_0006: call instance string [mscorlib]System.Int32::ToString()
        IL_000b: call void [mscorlib]System.Console::WriteLine(string)
        IL_0010: nop
        IL_0011: ldloc.0
        IL_0012: ldc.i4.1
        IL_0013: add
        IL_0014: stloc.0
        IL_0015: nop
        IL_0016: ldloc.0
        IL_0017: ldc.i4.7
        IL_0018: clt
        IL_001a: stloc.1
        IL_001b: ldloc.1
        IL_001c: brtrue.s IL_0003
    // end loop
    IL_001e: ret
} // end of method Program::While

.method private hidebysig 
    instance void Goto () cil managed 
{
    // Method begins at RVA 0x207c
    // Code size 34 (0x22)
    .maxstack 2
    .locals init (
        [0] int32 x,
        [1] bool CS$4$0000
    )

    IL_0000: nop
    IL_0001: ldc.i4.0
    IL_0002: stloc.0
    // loop start (head: IL_0003)
        IL_0003: ldloca.s x
        IL_0005: call instance string [mscorlib]System.Int32::ToString()
        IL_000a: call void [mscorlib]System.Console::WriteLine(string)
        IL_000f: nop
        IL_0010: ldloc.0
        IL_0011: ldc.i4.1
        IL_0012: add
        IL_0013: stloc.0
        IL_0014: ldloc.0
        IL_0015: ldc.i4.7
        IL_0016: clt
        IL_0018: ldc.i4.0
        IL_0019: ceq
        IL_001b: stloc.1
        IL_001c: ldloc.1
        IL_001d: brtrue.s IL_0021

        IL_001f: br.s IL_0003
    // end loop

    IL_0021: ret
} // end of method Program::Goto
ILSpy事件将goto标记为循环。将其反编译为C#时,它甚至将两个循环显示为
do while

但是有一个不同的!while循环有一个作用域:

        int x = 0;
        do
        {
            string z = "TEST";
            Console.WriteLine(x.ToString());
            ++x;
        }
        while (x < 7);
        Console.WriteLine(z); // invalid!
intx=0;
做
{
字符串z=“测试”;
Console.WriteLine(x.ToString());
++x;
}
x<7;
控制台。写入线(z);//无效的
但这是有效的:

        int x = 0;
    label:
        string z = "TEST";
        Console.WriteLine(x.ToString());
        ++x;
        if (x < 7) goto label;
        Console.WriteLine(z);
intx=0;
标签:
字符串z=“测试”;
Console.WriteLine(x.ToString());
++x;
如果(x<7)goto标签;
控制台写入线(z);

你应该用它吗?不请参阅答案。

goto创建意大利面代码。只有少数情况下可以接受使用goto,例如跳出多个嵌套循环和在switch语句中跳出大小写。-这两个代码段的执行没有区别,但是当您需要编写比这更复杂的代码时,使用
goto
的代码变得很难维护。相关:是的,下面的代码段唯一的“问题”是未来的维护者、代码审阅者或您的老板会感到困惑“难道他们不知道
和其他标准语言结构吗?”——“我还能在他们的代码中找到什么其他的精华呢?”?“显然,这个问题不能从一个片段中看出。想象一下大型项目和goto在页面上来回跳跃..没错,但在某些情况下,
循环是非常人工的,唯一的目的是避免
goto
。这并不是说有不同的实现方法,真的。在某些情况下,您必须进行跳转(少数特殊情况除外,它们有自己的指令,如
repnz
)。
的另一个好处是,您有一个重复的显式块-很容易看出,它隔离了块的局部变量,总之,它可以防止您犯许多小错误。当然,它更能抵抗代码修改——很容易意外地中断
goto
代码,尤其是在现在流行源代码管理的情况下(自动合并是一件痛苦的事情)。的确@Luaan。你应该防止使用
goto
,并且只有在你真的需要的时候才使用(我从来没有见过这种情况,但还好)。
        int x = 0;
        do
        {
            string z = "TEST";
            Console.WriteLine(x.ToString());
            ++x;
        }
        while (x < 7);
        Console.WriteLine(z); // invalid!
        int x = 0;
    label:
        string z = "TEST";
        Console.WriteLine(x.ToString());
        ++x;
        if (x < 7) goto label;
        Console.WriteLine(z);