Обработка исключений C # — будет ли последний блок catch извлекать повторно созданное исключение?

#c# #exception

Вопрос:

Мне интересно, будет ли этот код работать таким образом, что после 10 попыток CleanUp() будет вызван? Или throw new Exception() последний блок catch не будет пойман последним блоком catch?

 public void Process()
{
    try
    {}
    catch (MyException e)
    {           
        int retries = GetRetries();
        if(retries > 10)
        {
            _logger.LogError("Retried event already {retries} times. Giving up.", retries);
            throw new Exception("Giving up!");
        }

        Process();

    }
    catch (Exception e)
    {
        CleanUp();
    }
}
 

Комментарии:

1. Если вы хотите знать, что происходит при запуске кода, запустите код и посмотрите, что произойдет. Почему вы спрашиваете нас, что делает ваш код, когда вы его запускаете?

2. Не используйте исключения для обычного потока управления

3. Потому что код намного сложнее этого, и для создания фактического условия потребуется некоторое усилие. Поэтому я попытался упростить это настолько, насколько мог. И, надеюсь, общий вопрос ясен.

4. @silent Я думаю, вам не нужен ваш сложный код, чтобы проверить это — попробуйте

5. Если вы хотите повторить Process попытку, вам нужно иметь цикл, содержащий попытку вокруг Process с уловом, который будет выдан, как только вы достигнете порога повторной попытки. И затем вы можете попробовать поймать все это для CleanuUp (или, наконец, если это имеет больше смысла). Пустое try значение бессмысленно, если вы просто не показываете код в своем try для краткости.

Ответ №1:

Нет, это так не работает. Для любого заданного try / catch блока try соответствующими блоками может быть перехвачено только исключение, возникающее в catch . Исключения, создаваемые внутри catch блоков, не могут быть обнаружены другими catch блоками на том же уровне.

finally блоки позволяют запускать код, когда элемент управления покидает try / catch по какой-либо причине. Итак, если в конце вашего try уже есть a CleanUp , тогда вы просто измените свой final catch(Exception e) на finally и удалите CleanUp в конце try части.

Однако, если вы хотите запускаться только CleanUp тогда, когда управление покидает try / catch через исключение, вам не так повезло. В IL есть fault предложение, которое есть finally , но только для исключений, но это не представлено в C #.

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


Или вы можете имитировать try / catch / fault путем вложения try / catch блоков:

 try
{
    try
    {}
    catch (MyException e)
    {           
        int retries = GetRetries();
        if(retries > 10)
        {
            _logger.LogError("Retried event already {retries} times. Giving up.", retries);
            throw new Exception("Giving up!");
        }

        Process();

    }
}
catch
{
  //Act as fault
  CleanUp();
  throw;
}
 

Комментарии:

1. спасибо, это именно то, что я пытался прояснить.

2. Как написано, этот код ровно ничего не сделает, потому что это внутреннее try пустое и поэтому не выдает, поэтому внутреннее catch никогда не будет выполняться, и, следовательно, никаких исключений не будет происходить во внешнем try , и внешнее catch также не будет выполняться. Я подозреваю, что OP действительно хочет try обойти Process , если это означает повторную попытку кода.

3. @juharr — да, я воспринял это как «содержимое try опущенного для краткости». Пустые try блоки бессмысленны.