Будет ли Try / Наконец (без Catch) всплыть исключение?

80

Я почти уверен, что ответ ДА. Если я использую блок Try finally, но не использую блок Catch, тогда любые исключения будут пузыряться. Правильно?

Любые мысли о практике в целом?

Сет

Теги:
exception-handling

2 ответа

90
Лучший ответ

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

  • 0
    или если он вернется
  • 12
    @ Дэвид: Вы не можете вернуться из блока finally в C #.
Показать ещё 1 комментарий
53

Любые мысли о практике в целом?

Да. Быть осторожен. Когда ваш блок 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.) Содержимое файла может быть повреждено, но теперь вы ничего не можете с этим поделать. В конце концов дескриптор файла будет закрыт, поэтому он может быть скорее раньше, чем позже.

  • 5
    Еще больше примеров того, как мы на самом деле еще не объединились как индустрия, когда дело доходит до обработки ошибок. Не то чтобы я мог предложить что-то лучше, чем исключения, но я надеюсь, что в будущем будет что-то более вероятное, что приведет к тому, что правильный курс действий будет принят достаточно легко.
  • 0
    В vb.net для кода в блоке finally возможно узнать, какое исключение ожидает рассмотрения. Если установить иерархию исключений, чтобы отличить «не сделал этого; состояние иначе хорошо» от «состояние нарушено», можно запустить блок «Окончательно» только в том случае, если ожидающее исключение не является одним из плохих. Мне нравится, когда процедуры disposer / cleanup перехватывают исключения и генерируют исключение DisposerFailedException (которое относится к категории «плохих» и включает в себя исходное исключение как InnerException). Я хотел бы видеть стандартный интерфейс iDisposableEx с Dispose (Ex as Exception), чтобы облегчить это.
Показать ещё 3 комментария

Ещё вопросы

Сообщество Overcoder
Наверх
Меню