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

• Исключения. Исключениями обычно считаются аномалии во время выполнения, которые трудно (а то и невозможно) учесть на стадии программирования приложения. Примерами исключений могут быть попытка подключения к базе данных, которая больше не существует, открытие запорченного XML-файла или попытка установления связи с машиной, которая в текущий момент находится в автономном режиме. В каждом из упомянутых случаев программист (или конечный пользователь) обладает довольно низким контролем над такими "исключительными" обстоятельствами.

С учетом приведенных определений должно быть понятно, что структурированная обработка исключений в .NET — прием работы с исключительными ситуациями во время выполнения. Тем не менее, даже для дефектов и пользовательских ошибок, которые ускользнули от глаз программиста, исполняющая среда будет часто генерировать соответствующее исключение, идентифицирующее возникшую проблему. Скажем, в библиотеках базовых классов .NET 5 определены многочисленные исключения, такие как FormatException, IndexOutOfRangeException, FileNotFoundException, ArgumentOutOfRangeException и т.д.

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

На заметку! Чтобы сделать примеры кода максимально ясными, мы не будем перехватывать абсолютно все исключения, которые может выдавать заданный метод из библиотеки базовых классов. Разумеется, в своих проектах производственного уровня вы должны широко использовать приемы, описанные в главе.

<p id="AutBody_Root295">Роль обработки исключений .NET</p>

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

/* Типичный механизм перехвата ошибок в стиле С. */

#define E_FILENOTFOUND 1000

int UseFileSystem

{

  // Предполагается, что в этой функции происходит нечто

  // такое, что приводит к возврату следующего значения.

  return E_FILENOTFOUND;

}

void main

{

  int retVal = UseFileSystem;

  if(retVal == E_FILENOTFOUND)

    printf("Cannot find file...");  // H e удалось найти файл

}

Такой подход далек от идеала, учитывая тот факт, что константа E_FILENOTFOUND — всего лишь числовое значение, которое немногое говорит о том, каким образом решить возникшую проблему. В идеале желательно, чтобы название ошибки, описательное сообщение и другая полезная информация об условиях возникновения ошибки были помещены в единственный четко определенный пакет (что как раз и происходит при структурированной обработке исключений). В дополнение к специальным приемам, к которым прибегают разработчики, внутри API-интерфейса Windows определены сотни кодов ошибок, которые поступают в виде определений #define и HRESULT, а также очень многих вариаций простых булевских значений (bool, BOOL, VARIANT_BOOL и т.д.).

Перейти на страницу:

Похожие книги