我想知道是否有人仍然在C#中使用“goto”关键字语法,以及可能的原因。
我倾向于查看导致读者跳过代码的任何语句作为不好的做法,但是想知道是否有任何可靠的方案来使用这样的语法?
答案 0 :(得分:84)
有一些(罕见的)goto实际上可以提高可读性的情况。实际上,您链接的文档列出了两个示例:
goto的一个常见用途是将控制转移到特定的switch-case标签或switch语句中的默认标签。
goto语句对于摆脱深层嵌套循环也很有用。
以下是后一个例子:
for (...) {
for (...) {
...
if (something)
goto end_of_loop;
}
}
end_of_loop:
当然,还有其他方法可以解决这个问题,例如将代码重构为函数,在其周围使用虚拟块等等(有关详细信息,请参阅this question)。作为旁注,Java语言设计者决定完全禁止转到,而是引入一个带有标记的break 语句。
答案 1 :(得分:60)
我记得这部分
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
答案 2 :(得分:21)
我在Eduasync中广泛使用它来显示编译器在C#5中使用异步方法时为您生成的代码类型。您会在迭代器块中看到相同的内容。
在“普通”代码中,我记不起上次使用它了......
答案 3 :(得分:8)
goto非常适合打破许多循环,其中break不能很好地工作(比如错误条件),并且正如Kragen所说,编译器使用goto来生成switch语句和其他一些东西。
答案 4 :(得分:6)
我不记得曾经使用goto
。但是也许它改善了你真正永远不想退出的永久循环的意图(没有break
,但你仍然可以return
或throw
):< / p>
forever: {
// ...
goto forever;
}
然后,一个简单的while (true)
就足够了......
此外,你可能在你希望循环的第一次迭代在循环中间开始的情况下使用:查看here作为示例。
答案 5 :(得分:5)
编译器在各种生成的代码中使用goto
语句,例如在生成的迭代器块类型中(使用yield return
关键字时生成) - 我很确定生成的XML序列化类型也是在那里也有一些goto
陈述。
有关C#编译器处理此问题的原因/方式的详细信息,请参阅Iterator block implementation details: auto-generated state machines。
除了生成的代码之外,没有充分的理由在普通代码中使用goto
语句 - 它使代码更难理解,因此更容易出错。另一方面,在这样生成的代码中使用goto
语句可以简化生成过程,并且通常很好,因为没有人会读取(或修改)生成的代码,因为机器不会出错正在写作。
请参阅Go-to statement considered harmful,了解针对goto
的论据以及一段经典的编程历史。
答案 6 :(得分:2)
处理器实现至少一个jump instruction,我相信很多语句都会在实现或解释中使用它们。
使用3rd或4th代语言的好处之一是这些物理细节都是从我们身上抽象出来的。虽然我们应该注意law of leaky abstraction我认为我们也应该使用tools as they are intended(抱歉)。如果我正在编写代码并且goto
似乎是一个好主意,那么现在是重构的时候了。结构化语言的目的是避免这些“跳跃”并在我们的工程中创建逻辑流程。
我应该避免使用break
,但我不能忽视性能优势。但是,如果我有相互需要break
的嵌套循环,则需要重构。
如果有人可以建议使用goto
似乎比重构更好的话,我会很乐意撤回我的答案。
答案 7 :(得分:-4)
Goto永远不会更好。并继续,中断(在switch / case中除外),(multiple)return,并且throw也应该保持在最小的最小值。你永远不想逃离巢循环的中间。您总是希望循环控制语句具有所有循环控制。缩进有信息,所有这些声明都会丢弃这些信息。你不妨拿出所有的缩进。