Когда наконец запускается, если вы бросаете исключение из блока catch? - PullRequest
116 голосов
/ 12 октября 2009
try {
   // Do stuff
}
catch (Exception e) {
   throw;
}
finally {
   // Clean up
}

В блоке выше, когда вызывается блок finally? Перед броском е или, наконец, называется, а затем ловить?

Ответы [ 7 ]

117 голосов
/ 12 октября 2009

Он будет вызван после переброса e (т.е. после выполнения блока catch)

редактирование этого 7 лет спустя - одно важное замечание: если e не перехватывается блоком try / catch дальше вверх по стеку вызовов или обрабатывается глобальным обработчиком исключений, то блок finally может никогда не выполняется вообще.

74 голосов
/ 12 октября 2009

Почему бы не попробовать это:

outer try
inner try
inner catch
inner finally
outer catch
outer finally

с кодом (отформатировано для вертикального пространства):

static void Main() {
    try {
        Console.WriteLine("outer try");
        DoIt();
    } catch {
        Console.WriteLine("outer catch");
        // swallow
    } finally {
        Console.WriteLine("outer finally");
    }
}
static void DoIt() {
    try {
        Console.WriteLine("inner try");
        int i = 0;
        Console.WriteLine(12 / i); // oops
    } catch (Exception e) {
        Console.WriteLine("inner catch");
        throw e; // or "throw", or "throw anything"
    } finally {
        Console.WriteLine("inner finally");
    }
}
30 голосов
/ 12 февраля 2015

После прочтения всех ответов здесь, похоже, что окончательный ответ зависит :

  • Если вы повторно выбросили исключение в блоке catch, и это исключение было перехвачено в другом блоке catch, все выполняется в соответствии с документацией.

  • Однако, если повторно обработанное исключение не обрабатывается, функция finally никогда не выполняется.

Я тестировал этот пример кода в VS2010 с C # 4.0

static void Main()
    {
        Console.WriteLine("Example 1: re-throw inside of another try block:");

        try
        {
            Console.WriteLine("--outer try");
            try
            {
                Console.WriteLine("----inner try");
                throw new Exception();
            }
            catch
            {
                Console.WriteLine("----inner catch");
                throw;
            }
            finally
            {
                Console.WriteLine("----inner finally");
            }
        }
        catch
        {
            Console.WriteLine("--outer catch");
            // swallow
        }
        finally
        {
            Console.WriteLine("--outer finally");
        }
        Console.WriteLine("Huzzah!");

        Console.WriteLine();
        Console.WriteLine("Example 2: re-throw outside of another try block:");
        try
        {
            Console.WriteLine("--try");
            throw new Exception();
        }
        catch
        {
            Console.WriteLine("--catch");
            throw;
        }
        finally
        {
            Console.WriteLine("--finally");
        }

        Console.ReadLine();
    }

Вот вывод:

Пример 1: перебросить внутри другого блока try:
--вне попробуйте
---- внутренняя попытка
---- внутренний улов
---- внутренний наконец
- ваш улов
--В конце концов
Ура!

Пример 2: перебросить за пределы другого блока try:
--try
--catch

Необработанное исключение: System.Exception: было сгенерировано исключение типа 'System.Exception'.
в ConsoleApplication1.Program.Main () в C: \ local source \ ConsoleApplication1 \ Program.cs: строка 53

23 голосов
/ 12 октября 2009

Ваш пример будет вести себя идентично этому коду:

try {
    try {
        // Do stuff
    } catch(Exception e) {
        throw e;
    }
} finally {
    // Clean up
}

В качестве примечания: если вы действительно имеете в виду throw e; (то есть, выбросить то же самое исключение, которое вы только что поймали), намного лучше просто сделать throw;, поскольку это сохранит оригинальная трассировка стека вместо создания новой.

12 голосов
/ 13 января 2015

Если в блоке обработчика перехвата есть необработанное исключение, блок finally вызывается ровно ноль раз

  static void Main(string[] args)
  {
     try
     {
        Console.WriteLine("in the try");
        int d = 0;
        int k = 0 / d;
     }
     catch (Exception e)
     {
        Console.WriteLine("in the catch");
        throw;
     }
     finally
     {
        Console.WriteLine("In the finally");
     }
  }

Выход:

C: \ Users \ Администратор \ документы \ TestExceptionNesting \ Bin \ Release> TestExceptionNesting.exe

в попытке

в улове

Необработанное исключение: System.DivideByZeroException: попытка деления на ноль. в TestExceptionNesting.Program.Main (String [] args) в C: \ users \ administrator \ documents \ TestExceptionNesting \ TestExceptionNesting.cs: строка 22 * ​​1015 *

C: \ Users \ Администратор \ документы \ TestExceptionNesting \ Bin \ Release>

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

3 голосов
/ 12 октября 2009

Простой способ сказать также - отладить ваш код и заметить, когда, наконец, вызывается.

1 голос
/ 07 октября 2013

При тестировании с помощью консольного приложения C # код finally был выполнен после того, как было сгенерировано исключение: существовал «диалог ошибки приложения», и после выбора опции «Закрыть программу» в этом окне консоли был выполнен блок finally. Но, установив точку разрыва внутри блока кода finally, я никогда не смогу его достичь. Отладчик продолжает останавливаться на операторе throw. Вот мой тестовый код:

    class Program
    {
       static void Main(string[] args)
       {
          string msg;
          Console.WriteLine(string.Format("GetRandomNuber returned: {0}{1}", GetRandomNumber(out msg), msg) == "" ? "" : "An error has occurred: " + msg);
       }

       static int GetRandomNumber(out string errorMessage)
       {
         int result = 0;
         try
         {
            errorMessage = "";
            int test = 0;
            result = 3/test;
            return result;
         }
         catch (Exception ex)
         {
            errorMessage = ex.Message;
            throw ex;

         }
         finally
         {
            Console.WriteLine("finally block!");
         }

       }
    }

Отладка в VS2010 - .NET Framework 4.0

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...