为什么不建议使用这种“ goto”语句?

时间:2018-11-20 12:02:43

标签: c# goto

在公司中,我们是否在项目中完全使用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;
    }
}

我相信在这种情况下添加循环会牺牲代码的清晰度,并且我发现仅仅因为具有Retry逻辑而引用Polly是一个过大的杀伤力。

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

2 个答案:

答案 0 :(得分:2)

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

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;
    } 
  }
}

甚至更好(尤其是如果我们想拥有许多网址)-感谢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; 
     }  
   } 
 } 

答案 1 :(得分:0)

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

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

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

此链接明确提到切换和退出嵌套循环。这两种情况均不适用。