我应该使用goto语句吗?

5

我有一段像下面这样的代码:

try
{
Work:

   while(true)
   {
      // Do some work repeatedly...
   }
}
catch(Exception)
{
   // Exception caught and now I can not continue 
   // to do my work properly

   // I have to reset the status before to continue to do my work
   ResetStatus();

   // Now I can return to do my work
   goto Work; 
}

相比使用goto,有更好的替代方法吗?或者说这是一个好的解决方案吗?


为什么不在while循环内部放置try catch呢?这样就不需要用到goto了... - Chris
5
为什么会有踩(downvotes)?这是一个合理的问题。 - Alex K.
我认为它被踩是因为有人提到了Jeho...我的意思是goto ;) 很多人非常讨厌goto,虽然几乎从不需要或明智地使用它,但它仍然存在有其原因,并不是最邪恶的语句。 - dowhilefor
@AlexK.,我没有投反对票,但我投了关闭票。因为目前这个问题没有真正的答案。很多人可以给你关于最佳实践的意见,大多数人会讨厌goto语句,但总的来说,这是一个意见问题。 - nathan gonzalez
@AlexK.:我认为这是基本的代码审查,而这不是该网站的主要内容。虽然我并不是其中一个投票者,但出于这个原因,我考虑将其关闭。 - Chris
显示剩余4条评论
4个回答

16

听起来你非常想要一个循环。我会这样写:

bool successful = false;
while (!successful)
{
    try
    {
        while(true)
        {
            // I hope you have a break in here somewhere...
        }
        successful = true;
    }
    catch (...) 
    {
        ...
    }
}

你可能想要使用do/while循环,我更偏向于直接使用while循环,但这是个人偏好,我可以理解在这里使用do/while循环更为合适。

我不会使用goto,因为它会使代码难以理解。

当然,如果你真的希望一个无限循环,只需将try/catch放到循环内部:

while (true)
{
    try
    {
        ...
    }
    catch (Exception)
    {
        ...
    }
}

4
@Fake.It.Til.U.Make.It: 很抱歉,我不明白你的意思。 - Jon Skeet
1
那似乎不等价,他有while(true),这将在成功时不退出,除非我漏掉了什么。 - heisenberg
他正在从catch块中调用标签Work,这是在try块中的..这是有效的吗? - Anirudha
@Robert 我非常确定它与问题中给出的示例不等价。 - heisenberg
1
@kekekela,精确的代码等价性从未是答案的要求,而且原帖作者没有提供足够的信息来推断他原始代码的确切意图。 - Robert Harvey
显示剩余7条评论

10

Goto 极少是适当的构造。使用它会让99%的人看到你的代码会感到困惑,即使在技术上正确的使用它也会显著降低代码的可理解性。

在大多数情况下,重构代码将消除需要(或希望使用)goto 的情况。例如,在您的特定情况下,您可以简单地将 try/catch 移动到 while(true) 内部。将迭代的内部代码转换为单独的函数可能会使其更加清晰。

while(true)
{
  try
  {
      // Do some work repeatedly...
  }
  catch(Exception)
  {
   // Exception caught and now I can not continue 
   // to do my work properly

   // I have to reset the status before to continue to do my work
   ResetStatus();
  }
}

那不是Nick代码的等价物。他的代码在成功时退出。 - Snowbear
1
在我看来,它们是等价的,但是当while(true)成功退出时是怎么做到的呢? - heisenberg
@Servy:好吧,它可能会。但是在给定的代码中没有这样的东西,也没有提到。 - Sebastian Negraszus
@SebastianNegraszus 我们不知道 // Do some work repeatedly... 包含什么内容。它可能会打破循环,也可能不会。我的观点是这是可能的,但仍然不相关。 - Servy
@AlexeiLevenkov 是的,while(true)while(HaveToContinue),而 ExceptionSocketException,但无论如何还是加1。 - Nick
显示剩余4条评论

0
似乎更有意义的做法是将try/catch语句移到while循环中。然后,您可以仅处理错误,并且循环将继续正常进行,而无需使用标签和goto来路由控制流程。

-2

在每次迭代中捕获并恢复状态,即使在外部捕获也会起到同样的作用,在这里你仍然在循环中,可以决定是继续还是退出循环。

另外:从一开始就捕获Exception是错误的(如果你捕获StackOverflowExceptionMemoryLeachException,你要怎么办 - 编辑:这只是举个例子,请查看文档以了解实际可捕获的异常类型)。捕获你期望抛出的具体异常类型。

while(true)
{
    try
    {
        // Do some work repeatedly...
    }
    catch(FileNotFoundException) //or anything else which you REALLY expect.
    {
        // I have to reset the status before to continue to do my work
        ResetStatus();
        //decide here if this is till OK to continue loop. Otherwise break.
    }
}

对于那些在评论中非常聪明的人:为什么不捕获通用异常?


1
实际上,StackoverflowException本身就无法被捕获,就像其他一些真正致命的异常(例如OOM)一样。 - Servy
那只是一个例子。捕获异常是错误的 - 那就是我的意思。 - Tengiz
我在那个观点上持不同意见,但这与问题无关,因此我认为在这里讨论没有意义。 - Servy
2
尚未被踩,但是这应该作为评论,因为它与问题完全无关(样本代码经常需要更改以使其更简洁,并显示出问题)... - Alexei Levenkov
@Servy 没问题。我们都知道什么是对的,什么是不对的。 - Tengiz
显示剩余4条评论

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接