【问题标题】:Does anyone still use [goto] in C# and if so why? [closed]有人还在 C# 中使用 [goto],如果是,为什么? [关闭]
【发布时间】:2011-07-01 08:57:14
【问题描述】:

我想知道是否有人仍在 C# 中使用“goto”关键字语法,以及这样做的可能原因。

我倾向于将任何导致读者在代码中跳转的语句视为不好的做法,但我想知道是否有任何可信的场景可以使用这种语法?

Goto Keyword Definition

【问题讨论】:

  • “静止”是什么意思?是否有一段时间人们一直使用它 [在 c# 中]?
  • @Massif:“still”旨在强调将“goto”用作意大利面条代码的前奏以及源代码缺乏可读性的现代观点。您很少会看到包含这个特定关键字的任何代码示例,这就是我一开始有兴趣询问的原因。
  • 如果读者“跳来跳去”代码是不好的做法,那么您是否也避免使用“break”、“continue”、“throw”和“return”?它们都导致控制流中的分支,有时是非本地分支。与 goto 不同,“Throw”甚至不会告诉你它的去向。
  • 我使用goto 打破循环并根据特定条件返回开始语句
  • 我喜欢 goto。我试图避免它,因为人们说要避免它,因为它使代码更难阅读。学习了汇编语言和分支语句后,我想有时候,它可能会使代码更具可读性。我确实认为一种方法中的多种用途以及在代码中跳得太远可能弊大于利。但是,如果您认为 goto 在这里可以很好地工作,那么偶尔使用一个简单的 goto 不应该仅仅因为普遍的共识是避免它而让您竭尽全力避免它。

标签: c# .net coding-style goto


【解决方案1】:

在一些(罕见的)情况下,goto 实际上可以提高可读性。实际上,您链接到的文档列出了两个示例:

goto 的一个常见用途是将控制转移到特定的 switch-case 标签或 switch 语句中的默认标签。

goto 语句对于跳出深度嵌套的循环也很有用。

这是后一种情况的示例:

for (...) {
    for (...) {
        ...
        if (something)
            goto end_of_loop;
    }
}

end_of_loop:

当然,还有其他方法可以解决这个问题,例如将代码重构为函数,在其周围使用虚拟块等(详见this question)。作为旁注,Java 语言设计者决定完全禁止 goto 并引入 labeled break 语句。

【讨论】:

  • 通常我会尝试重构它以将循环放在一个单独的方法中,我可以从...返回...
  • @Heinzi - 我还没有看到 goto 得到保证。正如 Jon 所说,如果它被“授权”,那么代码就是在乞求重构。
  • 标记为 break,只是 goto 的一种更长的说法,因为它做同样的怪事......
  • @Jesus 但是使用 goto,你可以去任何地方。带标签的 break 确保你只是在循环之外。
  • 除非您喜欢冒险并使用带有地址的 goto(我以前见过),否则该问题会得到缓解。而且我怀疑有人在你的 C# 和 Java 代码中使用 detour hooks 来利用 goto 语句。
【解决方案2】:

我记得这部分

switch (a)     
{ 
    case 3: 
        b = 7;
        // We want to drop through into case 4, but C# doesn't let us
    case 4: 
        c = 3;
        break; 
    default: 
        b = 2;
        c = 4;
        break; 
}

这样的事情

switch (a)     
{
    case 3: 
        b = 7;
        goto case 4;    
    case 4: 
        c = 3;
        break;     
    default: 
        b = 2;
        c = 4;
        break;
}

参考This

【讨论】:

  • 我实际上认为这是使用 [goto] 的最正当理由。至少在这种情况下,它增加了程序员的可读性,他们不知道在没有 break 语句的情况下 case 会相互插入。
  • @Brian Scott,V4Vendetta。除非我弄错了,否则第一条语句不会在 C# 中编译。这将有助于程序员的理解。
  • V4Vendetta 为什么要在第一个代码 sn-p... 上插入中断?最好在没有中断的情况下显示它,否则两个 sn-ps 会做不同的事情。在第二个示例中需要 goto 的原因正是因为第一个示例不能在 C# 中编译(就像在 C 中那样)。
【解决方案3】:

我在 Eduasync 中广泛使用它来展示编译器在 C# 5 中使用异步方法时为您生成的代码类型。您会在迭代器块中看到相同的内容。

不过,在“普通”代码中,我不记得我上次使用它是什么时候了...

【讨论】:

  • 您能否提供一个小例子来说明为什么首选这种方法或者仅仅是个人偏好?
  • @Brian:你的意思不是很清楚。 Eduasync 显示了与编译器为您所做的等效的 C# 代码 - 它生成的代码有效地使用 goto...
【解决方案4】:

编译器在生成的各种代码中使用goto 语句,例如在生成的迭代器块类型中(使用yield return 关键字生成 - 我很确定生成的 XML 序列化类型也有一些 @ 987654325@ 语句也在某处。

有关 C# 编译器为何/如何处理此问题的更多详细信息,请参阅 Iterator block implementation details: auto-generated state machines

除了生成的代码之外,没有充分的理由在普通代码中使用 goto 语句 - 它使代码更难理解,因此更容易出错。另一方面,像这样在生成的代码中使用goto 语句可以简化生成过程并且通常没问题,因为没有人会阅读(或修改)生成的代码,并且不会因为机器正在做而出错写作。

请参阅 Go-to statement considered harmful 以了解反对 goto 的论点以及一段经典的编程历史。

【讨论】:

  • 这很愚蠢:有几种情况 goto 很有用,如其他答案所示。要么你明确地反驳它们,要么只是说“这是错误的”,嗯,是错误的。
  • @Lohoris 我不买它 - 我见过的每个例子 goto “提高可读性”(包括这里的答案)在一些简单的操作之后会更具可读性重构。
  • @Justin 不,有时嵌套循环只是做某事的最自然的方式,例如,如果您正在遍历数组数组。
  • @Justin 将其放入函数中并不总是更清楚。您强迫某些东西(具有功能)只是为了避免您虔诚地讨厌的东西(使用 goto)。明确指示做错了什么。
  • @Justin Functions 调用有开销。 goto 没有。需要考虑的事情。
【解决方案5】:

我不记得曾经使用过goto。但是也许它改善了你真的不想退出的永远循环的意图(没有break,但你仍然可以returnthrow):

forever: {
  // ...
  goto forever;
}

再一次,一个简单的while (true) 就足够了...

此外,您可以在您希望循环的第一次迭代在循环中间开始的情况下使用:查看here 的示例。

【讨论】:

  • 链接的答案包含goto.. 的“有趣”用法,而while(true) {..} 不是一个有趣的用法..
  • 这很有趣,但我不知道我是否会在生产代码中使用它
【解决方案6】:

goto 非常适合打破 break 无法正常工作的许多循环(比如在错误条件下),正如 Kragen 所说,编译器使用 goto 来生成 switch 语句和其他一些东西。

【讨论】:

  • 肯定“break”/“continue”是更好的循环管理方法,而不是要求代码编辑器在源代码中跳转以试图了解下一步发生的位置?
  • 如果您有嵌套循环,则不会。
  • 好的,我认为这是一个有效的场景。
  • 在错误情况下,应该考虑抛出异常。
  • 如果您想在内部毫无例外地处理错误,这将是一种有效的方法。
【解决方案7】:

处理器至少实现了一个jump instruction,我相信很多语句在它们的实现或解释中都使用了这些。

使用3rd4th 生成语言的好处之一是这些物理细节已从我们这里抽象出来。虽然我们应该注意law of leaky abstraction,但我认为我们也应该使用我们的tools as they are intended对不起)。如果我正在编写代码并且goto 似乎是个好主意,那么是时候重构了。结构化语言的目的是避免这些“跳跃”并在我们的工程中创建逻辑流程。

我应该避免使用break,但我不能忽视性能优势。但是,如果我有相互需要 break 的嵌套循环,那么是时候重构了。

如果有人可以提议使用goto 似乎比重构更好,我会很乐意撤回我的答案。

我希望我不会因为冲到这里的“bike shed”而感到内疚。正如 Kragen 所说,对Dijkstra 足够好的东西对我来说已经足够好了。

【讨论】:

  • 获取一个dynamic 对象并遍历它的对象图,其中包含多个字典以获取我需要的值。使用具有dynamic 参数但期望精确对象形状的方法没有意义。使用 goto 打破多个层并继续遍历这些对象的集合。 [我不拥有这些类型,所以我无法提供更好的访问,所以它是反射或动态的]
【解决方案8】:

Goto 再好不过了。并且 continue、break(除了 switch/case)、(multiple)return 和 throw 也应该保持在最低限度。你永远不想逃离嵌套循环的中间。你总是希望循环控制语句拥有所有的循环控制。缩进有信息,所有这些语句都会丢弃这些信息。你不妨把所有的缩进都去掉。

【讨论】:

  • 如果没有必要保持循环的执行,你会想要跳出循环。否则你最终会无缘无故地在更长的循环中浪费更多的处理时间。
  • @Kirk,这听起来像是一种观点,而不是任何量化的东西?
猜你喜欢
  • 2010-10-21
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2013-07-12
  • 1970-01-01
相关资源
最近更新 更多