Изменения, касающиеся необработанных исключений, которые появились в .NET 2.0

Когда исключение сгенерировано, исполняющая система начинает искать в стеке соответствующий этому исключению блок catch. Проходя по стеку, она раскручивает его, очищая по пути каждый фрейм.

Если поиск завершается в последнем фрейме потока, а обработчик исключения не найден, в этой точке исключение считается необработанным. Что случится дальше — зависит от того, какая версия .NET Framework используется кодом.

Для необработанных исключений можно установить специальный фильтр, зарегистрировав делегат с помощью AppDomain. UnhandledException. Когда необработанное исключение проходит сквозь весь стек, этот делегат будет вызван и получит экземпляр
UnhandledExceptionEventArgs.

Среда CLR транслирует необработанные исключения, проходящие через статические конструкторы.

В .NET 1.1 проектировщики CLR решили “проглатывать” некоторые необработанные исключения в интересах повышенной стабильности. Например, если финализатор генерирует исключение в .NET 1.1 вместо прерывания потока финализатора и всего процесса, то исключение “проглатывается” и не позволяет уничтожить поток финализатора или прервать процесс. Аналогично, если необработанное исключение проникает в поток, отличающийся от главного потока, этот поток прерывается, не затрагивая остального процесса.

В потоке, управляемом пулом потоков, исключение “проглатывается”, а поток возвращается в пул — такое поведение аналогично обработке исключения в потоке финализатора. Если необработанное исключение распространяется вверх из главного потока, оно ведет себя, как и ожидалось, при этом либо прерывается процесс, либо отображается диалог отладки JIT, спрашивающий у пользователя, что он желает предпринять.

Такое поведение выглядит неплохо в принципе, но в реальности дает результат, обратный ожидаемому. Вместо обеспечения повышенной стабильности, система приходит в нестабильное состояние, поскольку код выполняется в недетерминированном состоянии. Например, представим финализатор, выполняющий некоторую ответственную работу. Предположим, что на полпути выполнения этой работы сгенерировано исключение. Вторая половина работы финализатора останется невыполненной.

Система находится в потенциально нестабильном, незавершенном состоянии. Внешне все продолжает работать нормально, хотя состояние системы может быть далеким от нормы. На практике это вызывает значительную нестабильность, поскольку источники ошибок трудно найти, раз исключения “проглатываются”. Отладка этих проблем отличается повышенной сложностью, потому что точка во времени, где возникло исключительное условие, обычно находится задолго до того момента, когда замечена результирующая нестабильность.

В .NET 2.0 эта проблема решена за счет требования, чтобы любое необработанное исключение, кроме AppDomainUnloadException и ThreadAbortException, вызывало прерывание потока. Звучит грубо, но на самом деле это именно то поведение, которое должно показывать необработанное исключение. В конце концов, это необработанное исключение.

Теперь, если поток прерывается, как и должен, это означает генерацию красного флажка в точке исключения, что позволяет немедленно обнаружить проблему и устранить ее. Это всегда хорошо. Всегда желательно, чтобы ошибки проявились как можно раньше; никогда не следует “глотать” исключения, позволяя системе работать, как ни в чем не бывало.

Если все-таки возникнет желание эмулировать поведение .NET 1.1 в отношении необработанных исключений, то его можно затребовать, добавив следующую опцию в конфигурационный файл приложения:

1
2
3
4
5
<system>
<runtime>
<legacyUnhandledExceptionPolicy enabled="l"/>
</runtime>
</system>

Вы можете следить за любыми ответами на эту запись через RSS 2.0 ленту. Вы можете оставить ответ, или trackback с вашего собственного сайта.

Оставьте отзыв

XHTML: Вы можете использовать следующие теги: <a href="" title=""> <abbr title=""> <acronym title=""> <b> <blockquote cite=""> <cite> <code> <del datetime=""> <em> <i> <q cite=""> <s> <strike> <strong>

 
Rambler's Top100