Исключения, связанные с поврежденным состоянием (Corrupted State Exceptions)

90

В .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. Возврат операционной системе нулевого значения свидетельствует о завершении работы приложения без ошибок, в то время как возврат любого другого значения (обычно отрицательного числа) — о том, что в ходе его выполнения возникла какая-то ошибка.

Пройди тесты
Лучший чат для C# программистов