Когда, наконец, выполняется, если вы выбрали исключение из блока catch?

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

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

Ответ 1

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

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

Ответ 2

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

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

Ответ 3

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

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

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

Я тестировал этот пример кода в VS2010 w/С# 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:
--outer try
---- внутренняя попытка
---- внутренний улов
---- внутреннее окончательное
- уловный лоток
- окончательно Ура!

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

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

Ответ 4

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

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

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

Ответ 5

Если в блоке обработчика catch есть необработанное исключение, блок 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

в try

в catch

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

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

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

Ответ 6

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

Ответ 7

Тестирование с помощью приложения С# Console, код 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