代码之家  ›  专栏  ›  技术社区  ›  kofucii

在这种情况下使用“goto”是否可以接受?

  •  1
  • kofucii  · 技术社区  · 14 年前

    以下是伪代码:

    myGoto:
    try
    {
       // do some db updating
       myDB.doOptimisticConcurrency();
    
    } catch (MyConcExeption ex) {
    
       if (tried < fiveTimes) {
           myDB.Refresh();
           tried++;
           goto myGoto;
       }
    
    }
    

    我在一个方法中有几个try-catch块,我不想从一开始就为每个抛出的异常重新调用我的方法。正在使用 goto 在这种情况下可以接受吗?

    6 回复  |  直到 14 年前
        1
  •  16
  •   Giorgi    14 年前

    您可以将其更改为:

    while (tried < fiveTimes)
    try
    {
       // do some db updating
       myDB.doOptimisticConcurrency();
       break;
    }
    catch (MyConcExeption ex)
    {
       tried++;
       myDB.Refresh();
    }
    
        2
  •  13
  •   Jon Skeet    14 年前

    我不会使用“goto”,但您可能需要编写一个小的助手方法。例如:

    public static void TryMultiple<E>(Action action, int times) where E : Exception
    {
        E lastException = null;
        for (int i = 0; i < times; i++)
        {
            try
            {
                action();
                return; // Yay, success!
            }
            catch (E exception)
            {
                // Possibly log?
                lastException = exception;
            }
        }
        throw new RetryFailedException("Retry failed " + times + " times",
                                       lastException);
    }
    

    这只是一个解决方案的草图-你需要相应地调整它。无论如何,这基本上允许您在遇到半接受的异常时以可重用的方式执行重试。您可能会使用lambda表达式来表示该操作,或者有时只对单个方法调用使用一个方法组:

    TryMultiple<MyConcurrencyException>(myDB.doOptimisticConcurrency, 5);
    
        3
  •  3
  •   Tyler Treat    14 年前

    你可以用一个循环。

        4
  •  2
  •   Colin Hebert    14 年前

    使用goto几乎是不可接受的,它会导致 spaghetti code 和get your code less readable.

    在您的情况下,一个简单的循环将使您的代码更具可读性。

    让你的代码更不可读。

    在您的例子中,一个简单的循环将使您的代码更加可读。

    alt text

        5
  •  1
  •   Ed Swangren    14 年前

    如果情况不是特别的,那么你不应该抛出一个例外。为什么不向该方法添加一个retry参数,并且只在超过retry计数时在内部引发异常?

    编辑:正如其他人所建议的,循环也是更好的选择。但是,这看起来像您的方法,而不是包装在某些库中的、您无法修改的方法。如果我是正确的,我仍然使用retry参数,并且只在所有重试失败时抛出异常。如果您希望此方法在第一次尝试时有时会失败,那么这不应该是异常。

        6
  •  -1
  •   Ani    14 年前

    这更好:

    private void MyMethod()
    {
       MyMethod(5);
    }    
    
    private void MyMethod(int triesLeft)
    {
       if(triesLeft == 0)
          return;  // or throw
    
       try
       {
          // do some db updating
          myDB.doOptimisticConcurrency();
       }       
       catch (MyConcExeption ex) 
       {
           myDB.Refresh(); 
           MyMethod(triesLeft - 1);
       }
    }