有可能用goto做的一切吗?

时间:2013-09-29 00:17:17

标签: c# goto

我知道goto是一个糟糕的设计实践。但是想象一下,我们被困在一个荒岛上,只有我们的工具箱里有一些东西。那不会这样:

    int i = 0;
    while (i < 10) i++; 

与此相同:

    int i = 0;
    loop: if (i < 10) { i++; goto loop; }

使用条件逻辑,分配/更改变量,方法调用和跳转,你可以在c#中做任何你能做的事吗?

4 个答案:

答案 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没有必然存在本质上的错误。使它不应该使用的原因如下:

  • 容易被滥用,并且可以很好地控制正确使用;即使这样,它也会使代码难以阅读

  • 始终 可以使用更易读的结构,例如whiledofor,或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,我要么从头开始重写,要么在不允许的情况下退出。