Сработает ли код в операторе Finally, если я верну значение в блоке Try?

StackOverflow https://stackoverflow.com/questions/345091

Вопрос

Я просматриваю некоторый код для друга и говорю, что он использовал оператор return внутри блока try-finally.Работает ли код в разделе Finally по-прежнему, даже если остальная часть блока try этого не делает?

Пример:

public bool someMethod()
{
  try
  {
    return true;
    throw new Exception("test"); // doesn't seem to get executed
  }
  finally
  {
    //code in question
  }
}
Это было полезно?

Решение

Простой ответ:ДА.

Другие советы

Обычно, да.Раздел finally гарантированно выполнит все, что произойдет, включая исключения или оператор return .Исключением из этого правила является асинхронное исключение, происходящее в потоке (OutOfMemoryException, StackOverflowException).

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

Вот небольшой тест:

class Class1
{
    [STAThread]
    static void Main(string[] args)
    {
        Console.WriteLine("before");
        Console.WriteLine(test());
        Console.WriteLine("after");
    }

    static string test()
    {
        try
        {
            return "return";
        }
        finally
        {
            Console.WriteLine("finally");
        }
    }
}

В результате получается:

before
finally
return
after

Цитирую из MSDN

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

В общем, да, the finally запустится.

Для следующих трех сценариев, наконец, будет ВСЕГДА беги:

  1. Никаких исключений не происходит
  2. Синхронные исключения (исключения, которые возникают при обычном выполнении программы).
    Сюда входят исключения, совместимые с CLS, которые являются производными от System.Исключение и исключения, не совместимые с CLS, которые не являются производными от System.Исключение.Исключения, не совместимые с CLS, автоматически переносятся RuntimeWrappedException.C # не может выдавать исключения из-за жалоб, отличных от CLS, но такие языки, как C ++, могут.C # может вызывать код, написанный на языке, который может генерировать исключения, не совместимые с CLS.
  3. Асинхронное исключение ThreadAbortException
    Начиная с .NET 2.0, исключение ThreadAbortException больше не будет препятствовать запуску finally.Исключение ThreadAbortException теперь устанавливается до или после finally .Finally всегда будет выполняться и не будет прерван прерыванием потока, при условии, что попытка была фактически введена до того, как произошло прерывание потока.

В следующем сценарии finally не будет запущен:

Асинхронное исключение StackOverflowException.
Начиная с .NET 2.0, переполнение стека приведет к завершению процесса.Finally не будет запущен, если не будет применено дополнительное ограничение, чтобы сделать finally CER (Область ограниченного выполнения).ССВ не следует использовать в общем пользовательском коде.Их следует использовать только там, где важно, чтобы код очистки выполнялся всегда - в конце концов, процесс все равно завершается при переполнении стека, и поэтому все управляемые объекты будут очищены по умолчанию.Таким образом, единственное место, где CER должен быть релевантен, - это ресурсы, которые выделяются вне процесса, например, неуправляемые дескрипторы.

Как правило, неуправляемый код оборачивается каким-либо управляемым классом, прежде чем быть использованным пользовательским кодом.Управляемый класс-оболочка обычно использует SafeHandle для обертывания неуправляемого дескриптора.SafeHandle реализует критический завершитель и метод Release, который запускается в CER, чтобы гарантировать выполнение кода очистки.По этой причине вы не должны видеть, что CERS разбросаны по всему пользовательскому коду.

Таким образом, тот факт, что finally не выполняется при StackOverflowException, не должен влиять на пользовательский код, поскольку процесс все равно завершится.Если у вас есть какой-то крайний случай, когда вам действительно нужно очистить какой-то неуправляемый ресурс за пределами SafeHandle или CriticalFinalizerObject, то используйте CER следующим образом;но, пожалуйста, обратите внимание, что это плохая практика - неуправляемая концепция должна быть абстрагирована от управляемого класса (классов) и соответствующих безопасных дескрипторов по дизайну.

например ,,

// No code can appear after this line, before the try
RuntimeHelpers.PrepareConstrainedRegions();
try
{ 
    // This is *NOT* a CER
}
finally
{
    // This is a CER; guaranteed to run, if the try was entered, 
    // even if a StackOverflowException occurs.
}

Из этого есть очень важное исключение, о котором я не видел упоминания ни в каких других ответах, и которое (после программирования на C # в течение 18 лет) Я не могу поверить, что я не знал.

Если вы создаете или запускаете исключение из Любой сортировка внутри вашего catch блок (не просто странный StackOverflowExceptions и тому подобное), и у вас нет всей try/catch/finally блок внутри другого try/catch блок, ваш finally блок не будет выполнен.Это легко продемонстрировать - и если бы я не видел этого сам, учитывая, как часто я читал, что это всего лишь действительно странные, крошечные случаи, которые могут вызвать finally блокируйте, чтобы не выполнять, я бы в это не поверил.

static void Main(string[] args)
{
    Console.WriteLine("Beginning demo of how finally clause doesn't get executed");
    try
    {
        Console.WriteLine("Inside try but before exception.");
        throw new Exception("Exception #1");
    }
    catch (Exception ex)
    {
        Console.WriteLine($"Inside catch for the exception '{ex.Message}' (before throwing another exception).");
        throw;
    }
    finally
    {
        Console.WriteLine("This never gets executed, and that seems very, very wrong.");
    }

    Console.WriteLine("This never gets executed, but I wasn't expecting it to."); 
    Console.ReadLine();
}

Я уверен, что для этого есть причина, но странно, что это не стало более широко известно.(Это отмечено здесь например, но не где-либо в этом конкретном вопросе.)

Я понимаю, что опаздываю на вечеринку, но в сценарии (отличающемся от примера OP), где действительно генерируется исключение, MSDN заявляет (https://msdn.microsoft.com/en-us/library/zwc8s4fz.aspx): "Если исключение не перехвачено, выполнение блока finally зависит от того, выберет ли операционная система запуск операции размотки исключения".

Блок finally - это всего лишь гарантированный для выполнения, если какая-либо другая функция (например, Main), находящаяся дальше по стеку вызовов, перехватит исключение.Эта деталь обычно не является проблемой, потому что все программы на C # в средах выполнения (CLR и OS) выполняются на большинстве свободных ресурсов, которыми владеет процесс при выходе (дескрипторы файлов и т.д.).Однако в некоторых случаях это может иметь решающее значение:Операция с базой данных наполовину завершена, которую вы хотите зафиксировать соответственно.размотать;или какое-то удаленное соединение, которое может не быть автоматически закрыто операционной системой и затем блокирует сервер.

ДА.Это, по сути, и есть главный смысл заявления finally.Если не происходит чего-либо катастрофического (не хватает памяти, компьютер отключен от сети и т.д.), оператор finally всегда должен выполняться.

Он также не будет срабатывать при неперехваченном исключении и выполнении в потоке, размещенном в службе Windows

Finally не выполняется, когда в потоке, запущенном в службе Windows

finally не будет запускаться в случае, если вы выходите из приложения с помощью System.exit(0);как в

try
{
    System.out.println("try");
    System.exit(0);
}
finally
{
   System.out.println("finally");
}

результат был бы просто :попробуй

В 99% сценариев будет гарантировано, что код внутри finally однако блок будет запущен, подумайте об этом сценарии:У вас есть поток, который имеет try->finally блок (нет catch) и вы получаете необработанное исключение внутри этого потока.В этом случае поток завершит работу и его finally блок не будет выполнен (в этом случае приложение может продолжить работу)

Этот сценарий встречается довольно редко, но это только для того, чтобы показать, что ответ не ВСЕГДА "Да", в большинстве случаев "Да", а иногда, в редких случаях, "Нет".

Основная цель finally block - выполнить все, что написано внутри него.Это не должно зависеть от того, что происходит в try или catch .Однако с System.Environment.Exit(1) приложение завершит работу без перехода к следующей строке кода.

Лицензировано под: CC-BY-SA с атрибуция
Не связан с StackOverflow
scroll top