Управление С#-механизмом обработки исключений зиждется на четырех ключевых словах: try, catch, throw и finally. Они образуют взаимосвязанную подсистему, в которой использование одного из них предполагает использование другого. Программные инструкции, которые нужно проконтролировать на предмет исключений, помещаются в try-блок. Если исключение таки возникает в этом блоке, оно дает знать о себе выбросом определенного рода информации. Это выброшенное исключение может быть перехвачено программным путем с помощью catch-блока и обработано соответствующим образом. Системные исключения автоматически генерируются С#-системой динамического управления. Чтобы сгенерировать исключение вручную, используется ключевое слово throw. Любой код, который должен быть обязательно выполнен при выходе из try-блока, помещается в блок finally.
Ядром обработки исключений являются блоки try и catch. Эти ключевые слова работают "в одной связке"; нельзя использовать слово try без catch или catch без try. Вот каков формат записи try/catch-блоков обработки исключений:
t r y { // Блок кода, подлежащий проверке на наличие ошибок. }
catch (ExcepType1 exOb) {// Обработчик для исключения типа ExcepTypel. }
catch (ExcepType2 exOb) { // Обработчик для исключения типа ЕхсерТуре2. }
Здесь ЕхсерТуре — это тип сгенерированного исключения. После "выброса" исключение перехватывается соответствующей инструкцией catch, которая его обрабатывает. Как видно из формата записи try/catch-блоков, с try-блоком может быть связана не одна, а несколько catch-инструкций. Какая именно из них будет выполнена, определит тип исключения. Другими словами, будет выполнена та catch-инструкция, тип исключения которой совпадает с типом сгенерированного исключения (а все остальные будут проигнорированы). После перехвата исключения параметр ехОb примет его значение.
Задавать параметр ехОb необязательно. Если обработчику исключения не нужен доступ к объекту исключения (как это часто бывает), в задании параметра ехОb нет необходимости. Если исключение не генерируется, try-блок завершается нормально, и все его catch-инструкции игнорируются. Выполнение программы продолжается с первой инструкции, которая стоит после последней инструкции catch. Таким образом, catch-инструкция (из предложенных после try-блока) выполняется только в случае, если сгенерировано соответствующее исключение.
Пример обработки исключения
Известно, что попытка индексировать массив за пределами его границ вызывает ошибку нарушения диапазона. В этом случае С#-система динамического управления генерирует исключение типа IndexOutOfRangeException, которое представляет собой стандартное исключение, определенное языком С#. Демонстрация обработки исключений:
int [ ] nums = new int [ 4 ] ;
try { // Генерируем исключение, связанное с попаданием индекса вне диапазона
Обратите внимание на то, что nums — это int-массив для хранения четырех элементов. Однако в цикле for делается попытка индексировать этот массив от 0 до 9, и как только значение индекса устанавливается равным четырем, генерируется исключение типа IndexOutOfRangeException.
Во-первых, проверяемый код содержится внутри try-блока. Во-вторых, при возникновении исключения (в данном случае из-за попытки внутри for-цикла индексировать массив nums за границами его диапазона) выполнение try-блока прекращается, а само исключение перехватывается catch-инструкцией. Другими словами, управление программой передается catch-инструкции, независимо от того, все ли инструкции try-блока выполнились. При этом важно то, что инструкция catch не вызывается, а ей передается управление программой.
После выполнения catch-инструкции программа продолжится со следующей инструкции. Следовательно, чтобы ваша программа могла нормально продолжить свое выполнение, обработчик должен устранить проблему, которая стала причиной возникновения исключительной ситуации.
В инструкции catch параметр отсутствует, параметр необходим только в тех случаях, когда требуется доступ к объекту исключения. В некоторых случаях значение объекта исключения используется обработчиком для получения дополнительной информации об ошибке, но чаще всего достаточно просто знать о том, что исключение имело место. Следовательно, в отсутствии catch-параметра в обработчике исключения нет ничего необычного.
Однако можно сгенерировать исключение вручную, используя инструкцию throw. Формат ее записан таков: throw exceptOb;
Элемент exceptOb — это объект класса исключений, производного от класса Exception.
Объект исключения типа DivideByZeroException был создан с помощью оператора new в инструкции throw. Инструкция throw генерирует объект.
Иногда возникает потребность определить программный блок, который должен выполняться по выходу из try/catch-блока. Например, исключение может вызвать ошибку, которая завершает текущий метод и, следовательно, является причиной преждевременного возврата. Однако такой метод может оставить открытым файл или соединение с сетью, которые необходимо закрыть. Подобные обстоятельства — обычное явление в программировании, и С# предоставляет удобный путь выхода из них: блок finally.
Чтобы определить блок кода, подлежащий выполнению по выходу из try/catch-блока, включите в конец try/catch-последовательности блок finally. Общая форма записи последовательности try/catch-блоков, содержащей блок finally, выглядит следующим образом:
try {// Блок кода, предназначенный для обработки ошибок. }
catch (ExcepTypel exOb) { //Обработчик для исключения типа ExcepTypel. }
catch (ЕхсерТуре2 ехОb) { // Обработчик для исключения типа ЕхсерТуре2. }
finally {// Код завершения обработки исключений.}
Блок finally будет выполнен после выхода из try/catch-блока, независимо от условий его выполнения. Другими словами, при нормальном завершении try-блока или в условиях возникновения исключения содержимое finally-блока будет безусловно отработано. Блок finally выполнится и в том случае, если любой код внутри try-блока или любая из его catch-инструкций определены внутри метода.