Исключения, связанные с поврежденным состоянием
В .NET 4.0 появилось совершенно новое пространство имен под названием System.Runtime.ExceptionServices (которое поставляется в составе сборки mscorlib.dll). Это довольно небольшое пространство имен включает в себя всего два типа класса, которые могут применяться, когда необходимо снабдить различные методы в приложении (вроде Main()) возможностью перехвата и обработки "исключений, связанных с поврежденным состоянием" (Corrupted State Exceptions — CSE).
Платформа .NET всегда размещается в среде обслуживающей операционной системы (такой как Microsoft Windows). Имея опыт программирования приложений для Windows, можно вспомнить, что низкоуровневый API-интерфейс Windows обладает очень уникальным набором правил по обработке ошибок времени выполнения, которые немного похожи на предлагаемые в .NET приемы структурированной обработки исключений.
В API-интерфейсе Windows можно перехватывать ошибки чрезвычайно низкого уровня, которые как раз и представляют собой ошибки, связанные с "поврежденным состоянием". Попросту говоря, если ОС Windows передает такую ошибку, это означает, что с программой что-то серьезно не так, причем настолько, что нет никакой надежды на восстановление, и единственно возможной мерой является завершение ее работы.
При работе с .NET ошибка CSE может появиться только в случае использования в коде C# служб вызова платформы (для непосредственного взаимодействия с API-интерфейсом Windows) или применения поддерживаемого в C# синтаксиса указателей.
До выхода версии .NET 4.0 подобные низкоуровневые ошибки, специфичные для операционной системы, можно было перехватывать только с помощью блока catch, предусматривающего перехват общих исключений System.Exception. Однако с этим подходом была связана проблема: если каким-то образом возникало исключение CSE, которое перехватывалось в таком блоке catch, в .NET не предлагалось (и до сих пор не предлагается) никакого элегантного кода для восстановления.
Теперь, с выходом версии .NET 4.0, среда CLR больше не разрешает автоматический перехват исключений CSE в приложениях .NET. В большинстве случаев это именно то поведение, которое нужно. Если же необходимо получать уведомления о таких ошибках уровня ОС (обычно при использовании унаследованного кода, нуждающегося в таких уведомлениях), понадобится применять атрибут [HandleProcessCorruptedStateExceptions].
Важно понять, что данный атрибут может применяться к любому методу в приложении, и в результате его применения соответствующий метод получит возможность иметь дело с подобными низкоуровневыми ошибками, специфическими для операционной системы.
Чтобы увидеть хотя бы простой пример, давайте создадим следующий метод Main(), не забыв перед этим импортировать в файл кода C# пространство имен System.Runtime.ExceptionServices:
[HandleProcessCorruptedStateExceptions] static int Main(string[] args) { try { // Предполагаем, что в Маin() вызывается метод, // который отвечает за выполнение всей программы. RunMyApplication(); } catch (Exception ex) { // Если мы добрались сюда, значит, что-то произошло. // Поэтому просто отображаем сообщение // и выходим из программы. Console.WriteLine ("ОШИБКА! ", ex.Message); return -1; } return 0; }
Задача приведенного выше метода Main() практически сводится только к вызову второго метода, отвечающего за выполнение всего приложения. В данном примере будем полагать, что в этом втором методе RunMyApplication() интенсивно используется логика try/catch для обработки любой ожидаемой ошибки. Поскольку метод Main() был помечен атрибутом [HandleProcessCorruptedStateExceptions], в случае возникновения ошибки CSE перехват System.Exception получается последним шансом сделать хоть что-то перед завершением работы программы.
Метод Main() здесь возвращает значение int, а не void. Возврат операционной системе нулевого значения свидетельствует о завершении работы приложения без ошибок, в то время как возврат любого другого значения (обычно отрицательного числа) — о том, что в ходе его выполнения возникла какая-то ошибка.
Комментарии