以下2个C#片段之间的执行存在差异吗?
do
{
Console.WriteLine(x.ToString());
++x;
}
while (x < 7);
和
label:
{
Console.WriteLine(x.ToString());
++x;
}
if (x < 7) goto label;
我想弄清楚为什么这么糟糕。 感谢。
编辑:如果我添加括号,则代码段非常相似。
EDIT2:在Visual Studio中,我点击了Go to Disassembly,我得到以下代码:
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
和
label:
{
Console.WriteLine(x.ToString());
00000069 lea ecx,[ebp-40h]
0000006c call 63129C98
00000071 mov dword ptr [ebp-4Ch],eax
00000074 mov ecx,dword ptr [ebp-4Ch]
00000077 call 63148168
0000007c nop
++x;
0000007d inc dword ptr [ebp-40h]
}
00000080 nop
if (x < 7) goto label;
00000081 cmp dword ptr [ebp-40h],7
00000085 setge al
00000088 movzx eax,al
0000008b mov dword ptr [ebp-44h],eax
0000008e cmp dword ptr [ebp-44h],0
00000092 jne 00000097
00000094 nop
00000095 jmp 00000068
区别在于无条件跳跃。
答案 0 :(得分:9)
不,我甚至认为while
的实现方式与后面的相同。
使用goto
时的不好之处在于它鼓励在您的代码中来回传递(也称为“意大利面条代码&#39;这是一团糟”)。它使您的代码极难阅读,调试和分析,并且它引入了错误,因为您无法真正了解正在发生的事情。
while
的好处是,你可以理解它,编译器可以理解它,所以它可以给你很好的警告。
答案 1 :(得分:2)
让我们来看看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!
但这是有效的:
int x = 0;
label:
string z = "TEST";
Console.WriteLine(x.ToString());
++x;
if (x < 7) goto label;
Console.WriteLine(z);
你应该用吗?没有!请参阅Patricks回答。