Является ли использование "goto" приемлемым в этой ситуации? - PullRequest
1 голос
/ 18 октября 2010

псевдокод:

myGoto:
try
{
   // do some db updating
   myDB.doOptimisticConcurrency();

} catch (MyConcExeption ex) {

   if (tried < fiveTimes) {
       myDB.Refresh();
       tried++;
       goto myGoto;
   }

}

У меня есть несколько блоков try-catch в одном методе, и я не хочу повторно вызывать мой метод с самого начала для каждого сгенерированного исключения. Допустимо ли в этой ситуации использование goto?

Ответы [ 6 ]

16 голосов
/ 18 октября 2010

Вы можете изменить его на:

while (tried < fiveTimes)
try
{
   // do some db updating
   myDB.doOptimisticConcurrency();
   break;
}
catch (MyConcExeption ex)
{
   tried++;
   myDB.Refresh();
}
13 голосов
/ 18 октября 2010

Я бы не использовал "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);
}

Это всего лишь набросок решения - вам нужно соответствующим образом адаптировать его. В любом случае, это, в основном, позволяет вам повторять попытки перед лицом частично принятого исключения многократно. Вы, вероятно, будете использовать лямбда-выражение для выражения действия или иногда просто группу методов для одного вызова метода:

TryMultiple<MyConcurrencyException>(myDB.doOptimisticConcurrency, 5);
3 голосов
/ 18 октября 2010

Вы можете просто использовать цикл.

2 голосов
/ 18 октября 2010

Использование goto почти никогда не приемлемо, это приводит к коду спагетти и делает ваш код менее читабельным.

В вашем случае простой цикл сделает ваш код более читабельным.

alt text

1 голос
/ 18 октября 2010

Вы не должны создавать исключение, если ситуация не является исключением.Почему бы вам не добавить аргумент повторения к этому методу и вызвать исключение внутри, только если превышено число повторов?

РЕДАКТИРОВАТЬ: Как и другие предлагали, цикл также является лучшей альтернативой.Однако это похоже на ваш метод, а не на метод, заключенный в какую-то библиотеку, которую вы не можете изменить.Если я прав, я по-прежнему использую параметр retry и генерирую исключение, только если все попытки завершаются неудачно.Если вы ожидаете, что этот метод иногда завершится с ошибкой с первой попытки, это не должно быть исключением.

0 голосов
/ 18 октября 2010

Это намного лучше:

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);
   }
}
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...