我知道goto是一个糟糕的设计实践。但是想象一下,我们被困在一个荒岛上,只有我们的工具箱里有一些东西。那不会这样:
int i = 0;
while (i < 10) i++;
与此相同:
int i = 0;
loop: if (i < 10) { i++; goto loop; }
使用条件逻辑,分配/更改变量,方法调用和跳转,你可以在c#中做任何你能做的事吗?
答案 0 :(得分:4)
是的,您可以重新编写任何程序以获得相同的输出而不使用任何循环。方法调用都可以内联,因此您在技术上也不需要它们。当然,类和接口对任何逻辑都不是必不可少的。事实上,你可以用if,goto,赋值和添加来完成所有事情。也许你甚至不需要那么多。
答案 1 :(得分:4)
技术上?是的,一点没错。 Goto程序是完整的,因此您可以将所有内容表示为它们。最后,机器代码与goto程序非常相似,因为循环和东西都是使用条件跳转完成的。当然在.NET中,您将无法使用仅 goto。在某些时候,你会遇到一些地方,你要么使用其他代码,而不是那样的代码,或者你所在的地方,语言结构会强迫你做其他事情(制作类,方法,函数等)。但从技术上讲,是的。
你应该这样做吗?绝对不。 Goto程序很难维护,而且C#编译成Intermediary Language,它使用跳转但是在更高级别上,你可能会在执行此操作时失去大量的性能。此外,虚拟机可以在“普通”代码中优化很多,当您将其置于固定的goto模式中时,它无法进行优化。
顺便说一下。你的原始代码编译成这个IL,这本质上是你用goto写的(我的注释):
// i = 0
IL_0001: ldc.i4.0 // Load integer value 0 to stack
IL_0002: stloc.0 // i // Store stack value in local variable 0
// goto loop-condition
IL_0003: br.s IL_0009 // Jump to IL_0009
// loop-start:
// i = i + 1
IL_0005: ldloc.0 // i // Load variable 0 to stack
IL_0006: ldc.i4.1 // Load integer `1` to stack
IL_0007: add // Add top two stack values
IL_0008: stloc.0 // i // Store result in local variable 0
// loop-condition:
// if (i < 10) { goto loop-start }
IL_0009: ldloc.0 // i // Load variable 0 to stack
IL_000A: ldc.i4.s 0A // Load integer `10` to stack
IL_000C: clt // Compare top two stack values
IL_000E: stloc.1 // CS$4$0000 // Store stack value in local variable 1
IL_000F: ldloc.1 // CS$4$0000 // Load variable 1 to stack
IL_0010: brtrue.s IL_0005 // Jump to IL_0005 if stack value is true
答案 2 :(得分:4)
goto
没有必然存在本质上的错误。使它不应该使用的原因如下:
极 容易被滥用,并且可以很好地控制正确使用;即使这样,它也会使代码难以阅读
始终 可以使用更易读的结构,例如while
,do
,for
,或foreach
由于同时始终可以并且总是更好地使用其他内容,因此永远不应该实际使用goto
。
我听说的一个可能的例外是打破深度嵌套:
for (int x = 0; x < 100; x++)
for (int y = 0; y < 100; y++)
for (int z = 0; z < 100; z++)
if (condition)
goto end;
end: ;
VS
for (int x = 0; x < 100, !condition; x++)
for (int y = 0; y < 100, !condition; y++)
for (int z = 0; z < 100, !condition; z++)
要更直接地回答您的问题,是的,完全有可能使用goto
而不是while
s,do
等完成所有控制流...我甚至可能建议这对练习来说是一个很好的挑战,但不是在任何真正的代码中,并且尝试在汇编中编码而不是强迫自己使用goto
s可能是一种更好的学习体验。
答案 3 :(得分:1)
是的,有可能。最终,这是装配工作的方式。装配中没有循环这样的东西。要更改代码中的位置,必须使用等效的“goto”(通常为jmp
或某种形式的“branch”)或函数调用(如果存在)。
但是,如果我继承的代码库使用goto
s,我要么从头开始重写,要么在不允许的情况下退出。