为什么不推荐使用 'goto' 语句?

Why this 'goto' statement usage is not recommended?

我们公司正在就是否应该在项目中使用 goto 语句展开激烈争论。我个人认为它为以下需要重试 Web 服务调用的场景增加了清晰度。

const string primaryWebServiceUrl = "https://example.com/Server.asmx";
const string secondaryWebServiceUrl = "https://example2.com/Server.asmx";

using (var ws = new Server())
{
    ws.Url = primaryWebServiceUrl;

start:
    try
    {
        wsAction?.Invoke(ws);
    }
    catch
    {
        if (ws.Url == secondaryWebServiceUrl)
            throw;

        ws.Url = secondaryWebServiceUrl;
        goto start;
    }
}

我认为在这种情况下添加循环会牺牲代码的清晰度,而且我发现仅仅为了具有重试逻辑而引用 Polly 是一种矫枉过正的做法。

编辑:因为每个人都说不建议在这里使用 goto 语句,所以我想详细了解为什么不建议这样做以及它可能产生的不利影响。在我看来,这增加了清晰度,但我可以理解,如果使用不当,goto 语句的展开效果可能是负面的,但在上面提供的示例中,为什么不推荐使用 goto 方法?

goto 在 switch 语句之外的任何地方都被认为是非常糟糕的做法。有很多更好的结构。

您可以将 try/catch 逻辑移动到方法中并循环检查结果(可能是 true/false),然后继续调用该方法 - 而不是使用 goto

https://docs.microsoft.com/en-us/dotnet/csharp/language-reference/keywords/goto

这个 link 明确提到切换和退出 深度 嵌套循环。这些情况都不适用于此处。

有效,但不推荐;更可读的实现是这样的

using (var ws = new Server()) {
  ws.Url = primaryWebServiceUrl;

  // Keep doing ...
  while (true) {
    try {
      wsAction?.Invoke(ws);

      // ...until Invoke succeeds
      break; 
    }
    catch { //TODO: put expected Exception type here
      // Something is very wrong; rethrow the exception and leave the routine 
      if (ws.Url == secondaryWebServiceUrl)
        throw;

      ws.Url = secondaryWebServiceUrl;
    } 
  }
}

或者更好(特别是如果我们想要有很多 url)——感谢 Panagiotis Kanavos 的想法:

 string[] urls = new string[] {
   "https://example.com/Server.asmx",
   "https://example2.com/Server.asmx",
   "https://example3.com/Server.asmx", 
    ...
   "https://example123.com/Server.asmx", 
 };

 using (var ws = new Server()) {
   // Try each url from urls...
   for (int i = 0; i < urls.Length; ++i) {
     try {
       ws.Url = urls[i];
       wsAction?.Invoke(ws);

       // ... until success 
       break;  
     }
     catch {
       // The last url failed; rethrow the error
       if (i >= urls.Length - 1)
         throw; 
     }  
   } 
 }