Похоже, что это соответствует некоторому первоначальному тестированию, но я хотел бы знать, будет ли он гарантирован вернуться или в некоторых случаях он не может вернуться? Это критично для моего приложения, но я еще не нашел варианта использования, когда оно не вернется.
Я хотел бы получить опыт по этому вопросу.
Если я вернусь из блока try / finally в C #, всегда ли выполняется код в finally?
Ответы (4)
В нормальных условиях код в блоке finally будет выполняться независимо от того, что происходит внутри блоков try или catch. Неважно, вернетесь ли вы из метода или нет.
Есть случаи, когда это не так. Например, если код в блоке finally вызывает исключение, он перестанет выполняться, как любой другой блок кода.
Эрик Липперт написал гораздо более исчерпывающий ответ, в котором описаны дополнительные случаи: https://stackoverflow.com/a/10260233/53777
Что касается goto, ответ по-прежнему положительный. Рассмотрим следующий код:
try
{
Console.WriteLine("Inside the Try");
goto MyLabel;
}
finally
{
Console.WriteLine("Inside the Finally");
}
MyLabel:
Console.WriteLine("After the Label");
Полученный результат таков:
Внутри попытки
Внутри наконец
После этикетки
В остальных ответах есть ряд неточностей.
Управление передается блоку finally, когда элемент управления выходит из блока try обычно - то есть путем возврата, перехода, прерывания, продолжения или просто падения с конца. Управление передается блоку finally, когда управление покидает блок try через исключение, которое было перехвачено включающим блоком catch.
Во всех остальных случаях нет гарантии, что код в блоке finally будет вызван. Особенно:
Если код блока try переходит в бесконечный цикл или поток замораживается и никогда не размораживается, то код блока finally никогда не вызывается.
Если процесс приостановлен в отладчике, а затем агрессивно уничтожен, то блок finally никогда не вызывается. Если процесс работает без сбоев, блок finally никогда не вызывается.
Если шнур питания выдернут из стены, блок finally никогда не вызывается.
Если возникает исключение без соответствующего блока перехвата, то то, выполняется ли блок finally или нет, является деталью реализации среды выполнения. Среда выполнения может выбрать любое поведение при возникновении неперехваченного исключения. Оба варианта «не запускать блоки finally» и «запускать блоки finally» являются примерами «любого поведения», поэтому можно выбрать любой из них. Обычно среда выполнения спрашивает пользователя, хотят ли они подключить отладчик перед запуском блоков finally; если пользователь говорит «нет», то запускаются блоки finally. Но опять же: среда выполнения не требуется для этого. Это могло просто быстро потерпеть неудачу.
Вы не можете полагаться на то, что блоки finally всегда вызываются. Если вам требуется надежная гарантия выполнения кода, вам не следует писать пробную версию, вы должны написать ограниченная область выполнения. Правильное написание CER - одна из самых сложных задач в программировании на C #, поэтому внимательно изучите документацию, прежде чем пытаться писать код.
Между прочим, "забавный факт" об окончательно заблокированных gotos:
try { goto X; } finally { throw y; }
X : Console.WriteLine("X");
X - это недостижимая метка, на которую нацелен достижимый goto! Так что в следующий раз, когда вы будете на вечеринке, вы можете подумать: «Привет всем, может ли кто-нибудь создать программу на C # с недостижимой меткой, на которую нацелен достижимый goto?» и вы увидите, кто на вечеринке прочитал спецификацию достижимости, а кто нет!
unreachable label that is targetted by a reachable goto
? Или, может быть, это не кажется чем-то необычным, потому что я никогда не думал об этом до публикации, а теперь, после публикации, мне показали решение, которое простое, но трудно придумать (поэтому я пропустил сложную часть, прочитав сообщение) ? :)
- person qqqqqqq; 12.03.2020
catch
блоках тело? :)
- person qqqqqqq; 13.03.2020
false
у вас есть when M()
, где M()
- функция, которая переходит в бесконечный цикл. Возникает исключение, фильтр исключений запускается, чтобы узнать, обрабатывает ли его блок catch, но фильтр работает вечно, поэтому мы никогда не попадаем в блок catch.
- person Eric Lippert; 13.03.2020
void X() { try { ObtainAdminPowers(); DoSomethingDangerous(); } finally { ReleaseAdminPowers(); }}
, а DoSomethingDangerous
выдает исключение. Теперь предположим, что у нас есть try { X(); } catch (Exception) when (M()) { }}
. Метод M()
запускается до освобождения административных полномочий! Автор X
считает, что никакой другой код, кроме DoSomethingDangerous
, никогда не сможет использовать полномочия администратора, но автор ошибается!
- person Eric Lippert; 13.03.2020
X()
должен был определить Y()
следующим образом void Y() { try { X(); } catch (Exception) when (M()) { }}
вместо того, чтобы выдавать голые X()
:)
- person qqqqqqq; 13.03.2020
void X() { try { Obtain(); DoIt(); } catch { Release(); throw; } Release(); }
, который не напишет ни один здравомыслящий человек. Это один из прискорбных недостатков конструкции безопасности, присущих исключениям .NET.
- person Eric Lippert; 14.03.2020
M()
перед блоком finally
, или это была просто ужасная ошибка? Я не могу придумать какой-либо веской причины, чтобы это работало таким образом.
- person user2357112 supports Monica; 19.11.2020
try { M } finally { N }
имеет значение, отличное от { try { M } catch (Exception e) { N; throw; } N }
. Я понимаю мотивацию, но не могу не задаться вопросом, можно ли этого достичь без введения полностью отдельного примитива, связанного с исключениями.
- person Joker_vD; 21.11.2020
Вот некоторые примеры:
Environment.FailFast ()
try
{
Console.WriteLine("Try");
Environment.FailFast("Test Fail");
}
catch (Exception)
{
Console.WriteLine("catch");
}
finally
{
Console.WriteLine("finally");
}
На выходе только «Попробуй».
Stackoverflow
try
{
Console.WriteLine("Try");
Rec();
}
catch (Exception)
{
Console.WriteLine("catch");
}
finally
{
Console.WriteLine("finally");
}
Где Rec:
private static void Rec()
{
Rec();
}
Результатом будет только «Попытка», и процесс завершится из-за StackOverflow.
Необработанное исключение
try
{
Console.WriteLine("Try");
throw new Exception();
}
finally
{
Console.WriteLine("finally");
}
finally
блок.
- person N. M.; 01.12.2020
В случае фатальных исключений, завершающих работу приложения, блок finally не вызывается. Включает переполнение стека, исключения во время JIT вызываемых методов, фатальные исключения во время выполнения CLR.
Как указывает @mintech, если приложение зависает внутри блока, оно просто не дойдет до блока finally. Это включает ожидание объектов синхронизации, бесконечные циклы взаимоблокировок или даже пользовательский интерфейс, который не имеет возможности закрыть его.
return
никогда не происходит. - person Ry-♦   schedule 21.04.2012