Я почти уверен, что ответ - ДА. Если я использую блок Try finally, но не использую блок Catch, то любые исключения БУДУТ пузыриться. Верный?
Есть какие-нибудь мысли о практике в целом?
Сет
Я почти уверен, что ответ - ДА. Если я использую блок Try finally, но не использую блок Catch, то любые исключения БУДУТ пузыриться. Верный?
Есть какие-нибудь мысли о практике в целом?
Сет
Ответы:
Да, безусловно, будет. Предполагая, что ваш finally
блок, конечно, не генерирует исключение, и в этом случае он эффективно «заменит» тот, который был сгенерирован изначально.
Есть какие-нибудь мысли о практике в целом?
Да. Будьте осторожны . Когда ваш блок finally работает, вполне возможно, что он работает из- за необработанного, неожиданного исключения . Это означает, что что-то сломано и может произойти что- то совершенно неожиданное .
В этой ситуации, возможно, вам вообще не следует запускать код в блоках finally. Код в блоке finally может быть построен так, чтобы предполагать, что подсистемы, от которых он зависит, исправны, хотя на самом деле они могут быть глубоко сломаны. Код в блоке finally может усугубить ситуацию.
Например, я часто вижу такие вещи:
DisableAccessToTheResource();
try
{
DoSomethingToTheResource();
}
finally
{
EnableAccessToTheResource();
}
Автор этого кода думает: «Я делаю временную мутацию состояния мира; мне нужно восстановить состояние, которое было до того, как меня вызвали». Но давайте подумаем обо всех случаях, когда это могло пойти не так.
Во-первых, доступ к ресурсу уже мог быть отключен вызывающей стороной; в этом случае этот код повторно включает его, возможно, преждевременно.
Во-вторых, если DoSomethingToTheResource выдает исключение, правильно ли сделать, чтобы разрешить доступ к ресурсу ??? Код, управляющий ресурсом, неожиданно сломан . По сути, этот код говорит: «Если код управления сломан, убедитесь, что другой код может вызвать этот сломанный код как можно скорее, чтобы он тоже мог выйти из строя ужасно ». Это кажется плохой идеей.
В-третьих, если DoSomethingToTheResource генерирует исключение, то как мы узнаем, что EnableAccessToTheResource также не будет генерировать исключение? Какой бы ужас ни случился, использование ресурса может также повлиять на код очистки, и в этом случае исходное исключение будет потеряно, а проблему будет труднее диагностировать.
Я обычно пишу такой код без использования блоков try-finally:
bool wasDisabled = IsAccessDisabled();
if (!wasDisabled)
DisableAccessToTheResource();
DoSomethingToTheResource();
if (!wasDisabled)
EnableAccessToTheResource();
Теперь состояние не изменяется, если в этом нет необходимости. Теперь состояние вызывающего абонента не изменится. И теперь, если DoSomethingToTheResource дает сбой, мы не включаем доступ повторно. Мы предполагаем, что что-то глубоко сломано, и не рискуем ухудшить ситуацию, пытаясь продолжить выполнение кода. Пусть звонящий сам решит проблему, если сможет.
Итак, когда лучше запустить блок finally? Во-первых, когда ожидается исключение. Например, вы можете ожидать, что попытка заблокировать файл может потерпеть неудачу, потому что кто-то другой заблокировал его. В этом случае имеет смысл перехватить исключение и сообщить об этом пользователю. В этом случае снижается неуверенность в том, что сломано; вы вряд ли сделаете хуже, прибравшись.
Во-вторых, когда очищаемый ресурс является дефицитным системным ресурсом. Например, имеет смысл закрыть дескриптор файла в блоке finally. («Использование» - это, конечно, всего лишь еще один способ написания блока try-finally.) Содержимое файла может быть повреждено, но сейчас вы ничего не можете с этим поделать. В конце концов дескриптор файла будет закрыт, так что это может быть скорее раньше, чем позже.