Я рассматриваю некоторый код для друга и говорю, что он использовал оператор return внутри блока try-finally. Код в разделе, наконец, все еще срабатывает, хотя остальная часть блока try не запускается?
Пример:
public bool someMethod()
{
try
{
return true;
throw new Exception("test"); // doesn't seem to get executed
}
finally
{
//code in question
}
}
c#
.net
exception-handling
try-catch
JamesEggers
источник
источник
StackOverflowException
,ExecutionEngineException
некоторые из них. И так как они не могут быть обработаны,finally
не будет работать.try
блоке. Ничего о резких программах не прерывается.try
блока - этоreturn
утверждение. (Второе утверждение этого блока недостижимо и выдаст предупреждение.)Ответы:
Простой ответ: да.
источник
finally
блок будет выполнен.Обычно да. Секция finally гарантированно выполнит все, что происходит, включая исключения или оператор возврата. Исключением из этого правила является асинхронное исключение, происходящее в потоке (
OutOfMemoryException
,StackOverflowException
).Чтобы узнать больше об асинхронных исключениях и надежном коде в таких ситуациях, прочитайте об ограниченных областях выполнения .
источник
Вот небольшой тест:
Результат:
источник
WriteLine
фактически выполняется результат для вызова метода. В этом случаеreturn
вызов устанавливает результат метода, наконец записывает в консоль - до выхода из метода. ЗатемWriteLine
метод Main выплевывает текст из обратного вызова.Цитирование из MSDN
источник
finally
в сущности , неверен: фактически он ничего не гарантирует даже для совершенно обычных программ (которые, как оказалось, выдали это исключение).Вообще-то да, наконец-то побежит.
В следующих трех сценариях всегда будет выполняться команда finally :
Это включает CLS-совместимые исключения, которые происходят из System.Exception и не-CLS-совместимых исключений, которые не происходят из System.Exception. Исключения, не совместимые с CLS, автоматически включаются в исключение RuntimeWrappedException. C # не может генерировать исключения, не относящиеся к CLS, но такие языки, как C ++, могут. C # может вызывать код, написанный на языке, который может генерировать исключения, не совместимые с CLS.
Начиная с версии .NET 2.0 исключение ThreadAbortException больше не будет препятствовать запуску finally. ThreadAbortException теперь поднимается до или после finally. Команда finally всегда будет выполняться и не будет прервана прерыванием потока, если попытка действительно была введена до прерывания потока.
В следующем сценарии, наконец, не будет работать:
Асинхронное исключение StackOverflowException.
Начиная с .NET 2.0 переполнение стека приведет к завершению процесса. Команда finally не будет запущена, если не будет применено дополнительное ограничение, чтобы окончательно сделать CER (область ограниченного выполнения). CER не должны использоваться в общем коде пользователя. Их следует использовать только в тех случаях, когда крайне важно, чтобы код очистки всегда выполнялся - после того, как весь процесс завершится из-за переполнения стека, и поэтому все управляемые объекты будут очищены по умолчанию. Таким образом, единственное место, в котором CER должен быть релевантным, - это ресурсы, которые выделены вне процесса, например, неуправляемые дескрипторы.
Как правило, неуправляемый код переносится каким-либо управляемым классом перед использованием пользовательским кодом. Управляемый класс-оболочка обычно использует SafeHandle для переноса неуправляемого дескриптора. SafeHandle реализует критический финализатор и метод Release, который запускается в CER, чтобы гарантировать выполнение кода очистки. По этой причине вы не должны видеть, что CER замусорены из-за кода пользователя.
Поэтому тот факт, что finally не запускается в StackOverflowException, не должен влиять на пользовательский код, так как процесс все равно будет завершен. Если у вас есть крайний случай, когда вам нужно очистить какой-то неуправляемый ресурс вне SafeHandle или CriticalFinalizerObject, то используйте CER следующим образом; но, пожалуйста, обратите внимание, что это плохая практика - неуправляемая концепция должна быть абстрагирована от управляемого класса (-ов) и соответствующих SafeHandle (-ов) по своему замыслу.
например,
источник
FailFast
внутренне. Единственный способ, которым мне удалось их поймать, - это настроить хостинг CLR . Обратите внимание, что ваша точка все еще действительна для некоторых других асинхронных исключений.Есть очень важное исключение из этого, о котором я не упоминал ни в каких других ответах, и которое (после программирования на C # в течение 18 лет) я не могу поверить, что не знал.
Если вы бросаете или запускаете исключение любого рода внутри вашего
catch
блока (не только странноStackOverflowExceptions
и тому подобное), и у вас нет всегоtry/catch/finally
блока внутри другогоtry/catch
блока, вашfinally
блок не будет выполняться. Это легко продемонстрировать - и если бы я сам этого не видел, учитывая, как часто я читал, что это действительно странные, крошечные угловые случаи, которые могут привести к тому, чтоfinally
блок не будет выполнен, я бы не поверил.Я уверен, что есть причина для этого, но странно, что это не так широко известно. (Это отмечено здесь, например, но нигде в этом конкретном вопросе.)
источник
finally
блок просто не является уловкой дляcatch
блока.Я понимаю, что опаздываю на вечеринку, но в сценарии (отличающемся от примера ОП), где действительно исключение выдается состояниями MSDN ( https://msdn.microsoft.com/en-us/library/zwc8s4fz.aspx ): «Если исключение не обнаружено, выполнение блока finally зависит от того, выберет ли операционная система запуск операции исключения».
Блок finally гарантированно будет выполняться только в том случае, если какая-либо другая функция (например, Main), находящаяся далее в стеке вызовов, перехватывает исключение. Эта деталь обычно не является проблемой, поскольку все программы C # во время выполнения (CLR и OS) работают на большинстве ресурсов, которыми владеет процесс при выходе (дескрипторы файлов и т. Д.). В некоторых случаях это может быть важно, хотя: Половина выполняемой операции с базой данных, которую вы хотите зафиксировать, соответственно. размотать; или какое-либо удаленное соединение, которое не может быть автоматически закрыто ОС и затем блокирует сервер.
источник
Да. Это на самом деле главный пункт окончательного утверждения. Если не произойдет что-либо, вызывающее катафрофизм (нехватка памяти, отключение компьютера и т. Д.), Всегда должен выполняться оператор finally.
источник
finally
блока, если это исключение никогда не перехватывается. Это застало меня врасплох ;-).Он также не будет запускаться при возникновении необработанного исключения и выполняться в потоке, размещенном в службе Windows.
Наконец, не выполняется, когда в потоке, работающем в службе Windows
источник
наконец, не запустится, если вы выходите из приложения, используя System.exit (0); как в
результат будет просто: try
источник
c#
, но это, кажется, такJava
. И кроме того, в большинстве случаевSystem.exit()
это намек на плохой дизайн :-)В 99% случаев будет гарантировано, что код внутри
finally
блока будет выполняться, однако подумайте о следующем сценарии: у вас есть поток с блокомtry
->finally
(нетcatch
), и вы получаете необработанное исключение в этом потоке. В этом случае поток завершится, и егоfinally
блок не будет выполнен (в этом случае приложение может продолжить работу).Этот сценарий довольно редок, но он только показывает, что ответом не всегда является «Да», чаще всего «Да», а иногда, в редких случаях, «Нет».
источник
Основная цель блока finally - выполнить все, что написано внутри него. Это не должно зависеть от того, что происходит в try или catch. Однако с System.Environment.Exit (1) приложение будет закрываться без перехода к следующей строке кода.
источник