В .NET, что, если что-то выйдет из строя в блоке catch, всегда будет вызвано?

В блоке try / catch / finally, например:

try
{

}
catch()
{
   // code fails here
}
finally
{ 

}

Итак, если в блоке catch есть исключение, всегда ли будет вызываться?

Что если нет finally, запустится ли код после блока catch?

Ответов (7)

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

  • В случае возникновения исключения StackOverflowException во время выполнения
  • System.Environment.FastFail
  • Environment.Exit
  • Если «фоновый» поток завершается, потому что завершается основная программа, которой он принадлежит.
  • Неожиданное выключение :)

Да, наконец, всегда будет работать

Нет, код после блока catch запускаться не будет.

Даже с блоком finally любой код, следующий за блоком finally, не будет запущен.

Блок finally всегда будет выполняться. Если вы исключаете блок finally, и внутри блока catch возникает исключение, то никакой код после блока catch не будет выполняться, потому что, по сути, ваш блок catch завершится ошибкой и сам сгенерирует необработанное исключение.

Если в блоке catch есть исключение, метод finally будет выполнен, но будет сгенерировано новое исключение. Блок catch, в котором возникло исключение, не перехватит исключение, он продолжит работу по стеку.

Извлеченный урок: не делайте в блоке catch вещей, которые могут бросить, если вы можете ему помочь; если необходимо, вложите блок try / catch.

try
{

}
catch()
{
  try
  {
    // code fails here
  }
  catch
  {
    // handle that. Or not. 
  }
}
finally
{ 

}

Блок finally всегда будет выполняться. Из MSDN :

Блок finally полезен для очистки любых ресурсов, выделенных в блоке try, а также для запуска любого кода, который должен выполняться, даже если есть исключение. Управление всегда передается блоку finally, независимо от того, как завершается блок try.

В то время как catch используется для обработки исключений, возникающих в блоке инструкций, finally используется для гарантии того, что блок инструкций кода выполняется независимо от того, как был завершен предыдущий блок try.

Кстати, это вопрос такого типа, который вы можете легко проверить, написав код, скомпилировав его и посмотрев, что происходит, когда вы его выполняете.

class Program {
    static void Main(string[] args) {
        try {
            Console.WriteLine("Trying!");
            throw new Exception();
        }
        catch (Exception e) {
            Console.WriteLine("Catching {0}!", e.Message);
            throw new Exception();
        }
        finally {
            Console.WriteLine("Finally!");
        }
    }
}

Это выводит:

Trying!
Catching Exception of type 'System.Exception' was thrown.!

Unhandled Exception: System.Exception: Exception of type 'System.Exception' was
thrown.
at TestFinally.Program.Main(String[] args) in C:\Documents and Settings\Me\My
Documents\Visual Studio 2008\Projects\TestFinally\TestFinally\Program.cs:line 15
Finally!
Press any key to continue . . .

Предполагая, что процесс не завершается внезапно (или, конечно, зависает), всегда будет выполняться блок finally.

Если блока finally нет, исключение из блока catch будет просто выброшено в стек. Обратите внимание, что исходное исключение, которое вызвало выполнение блока catch, будет фактически потеряно.

Исключения переполнения стека

Как заметил Джаред, переполнение стека приведет к тому, что блок finally не будет выполнен. Я считаю, что это резко завершает программу, но я могу ошибаться. Вот пример кода:

using System;

public class Test
{    
    static void Main()
    {
        // Give the stack something to munch on
        int x = 10;
        try
        {
            Main();
            Console.WriteLine(x);
        }
        finally
        {
            Console.WriteLine("Finally");
        }
    }  
}

Полученные результаты:

Процесс прекращен из-за исключения StackOverflowException.

Если в блоке catch возникает исключение, весь код в finally все равно будет выполнен. Если есть обработчик исключения выше в стеке (например, вызывающий эту функцию), он перехватит это исключение. В противном случае приведет к необработанному исключению и остановит ваше приложение.

Код после точки исключения в блоке catch не вызывается.