【问题标题】:What is the best way to avoid goto?避免 goto 的最佳方法是什么?
【发布时间】:2012-09-19 11:08:34
【问题描述】:

我通常会陷入这样一种情况,即 goto 似乎是我心目中的最佳选择。但是看了好几遍都没用,总有替代的。现在,我正在尝试这样的事情:-

    try{
            //Something that requires internet connectivity;
    }
     catch{
            //Show a message-Internet connectivity lost,and go back to try
    //-->FYI--Ignore "show message", because I am just appending this text to a  
    // textbox. So there won't be a problem of multiple ShowMessage Boxes.
      }

现在,在我看来,最好的选择是在 catch 语句中使用 goto,但我试图避免它。 try 是函数中的第一个语句,如果我记得那个函数,我正在堆积堆栈,所以这也不是一个更好的选择。我可以采取什么替代方案?

【问题讨论】:

  • 是否可以为此创建一个函数?
  • 你的意思是try块里面的所有东西?是的,代码很简单,我可以为它创建一个函数,或者我不明白你的意思?
  • “但我读了好几遍都没用”——你在哪里读到的? Edsger W. Dijkstra 的引述是关于在特定语言中过度使用 GOTO
  • 是的,您没看错,然后您再次调用该函数。但也请检查下面的答案。他们可能会提供更好的选择
  • @Oded:我在一本 C 的书(Yashwant Kanetkar)中读到它,因为这是我的第一本编程书,所以它的一切都在我脑海中浮现(就像有人告诉你鬼故事一样在童年时期,他们永远卡住了)。我清楚地记得那句话——“避免使用 goto,它们让程序员的生活变得悲惨”:-D。但是,它通常会使我的工作更简单。

标签: c# goto


【解决方案1】:

使用带有标志的while 循环

var tryAgain = true;
while (tryAgain) 
{
    try
    {
        ...
        tryAgain = false;
    }
    catch (...)
    {
        tryAgain = ...
    }
}

【讨论】:

  • 使用带有标志的while循环?严重地?!如果发生严重错误怎么办,比如除以零。循环只是变成一个无限循环,整个解决方案都会中断!这只会使问题难以诊断。我对此表示反对。
  • @undefinedbehaviour 你会捕捉到一个 specific 异常,你不会在这里捕捉到 any 异常,所以如果出现问题,异常会冒泡 - 正如你所期望的那样。
  • 您认为this link 有何建议?
  • 该链接表明在特定情况下您可能会失去一些编译器优化,这可能是毫秒...
【解决方案2】:

在这种特殊情况下,递归调用相同的函数并保持计数器记录您调用它的次数并没有错。像这样的东西(在伪代码中):

public void DoMyInternetThing(int numberOfAttemptsRemaining)
{
    try 
    {
         //do stuff
    }
    catch (ConnectionException) 
    {
        if (numberOfAttemptsRemaining <= 0)
            throw new SomethingBadHappenedException();

        DoMyInternetThing(numberOfAttemptsRemaining - 1);  
    }
}

与任何递归一样,您需要确保正确构建它,但这很好用(我自己使用过)并且它避免了您的goto(这本身并不坏,但使用它会导致意大利面条或结构不良的代码)。

【讨论】:

  • 我认为您的意思是 --numberOfAttemptsRemaining,因为您的代码会在重试次数过多或更好地使用 numberOfAttemptsRemaining-1 后导致堆栈溢出。
  • 为了可读性,我会选择numberOfAttemptsRemaining - 1,因为它很容易出错,而且您正在更改方法的输入参数,而没有真正的需要。仍然为您的解决方案 +1。
  • @Steven --numberOfAttemptsRemaining 适用于我的结构,它避免了在抛出时弹出然后递归回来,因为 numberOfAttemptsRemaining 的本地副本没有改变。在任何情况下,我都对其进行了重组以使其更具可读性(尽管这意味着抛出一个新异常,而不仅仅是使用throw)。
  • @slugster:IMO,你的答案应该被标记为答案。
  • @Steven OP 没有提及最大尝试次数。因此,我不同意它“应该被标记为答案”,因为它不能解决开箱即用的 OPs 问题。我根本不会敲这个解决方案,因为我可以看到它会派上用场。但是,它有点不灵活,因为它使用户无法控制是否要重试,它会自动发生。
【解决方案3】:

如果您想再试一次,请将您的 try-catch 包装在一个 do-while 循环中。

【讨论】:

  • 里面有什么??就像在 catch 块内将变量设置为 true 并在 while 内测试它?是的,这似乎是一个不错的选择。
猜你喜欢
  • 2011-01-12
  • 2019-08-23
  • 2014-12-15
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2010-10-10
  • 2010-09-08
相关资源
最近更新 更多