В С# исключения представляются классами. Все классы исключений должны быть выведены из встроенного класса исключений Exception, который является частью пространства имен System. Таким образом, все исключения – подклассы класса Exception. Класс Exception имеет два производных класса SystemException и ApplicationException, поддерживающие две общие категории исключений:
- исключения, которые генерируются общей системой поддержки времени выполнения С#;
- исключения, которые генерируются прикладными программами С#.
В обработке исключений используются несколько ключевых слов языка: try, саtch, finallу, throw, использование которых взаимосвязано. Так например ключевые слова саtch, finallу нельзя использовать без ключевого слова try.
Программные инструкции, которые нужно проконтролировать на предмет исключений, помещаются в try -блок. Оператор try содержит три части:
- контролируемый блок, предваряемый ключевым словом trу. В контролируемый блок включаются потенциально опасные операторы программы. Все функции, прямо или косвенно вызываемые из блока, также считаются ему принадлежащими;
- один или несколько обработчиков исключений – блоков саtch, в которых описывается, как обрабатываются ошибки различных типов;
- блок завершения finallу выполняется независимо от того, возникла ошибка в контролируемом блоке или нет.
Рассмотрим, каким образом реализуется обработка исключительных ситуаций.
- Обработка исключения начинается с появления ошибки. Функция или операция, в которой возникла ошибка, генерирует исключение. Часто оно генерируется в функциях, вложенных в блок try.
- Выброшенное исключение может быть перехвачено программным путем с помощью catch -блока и обработано соответствующим образом.
- Если обработчик не найден, вызывается стандартный обработчик исключения. Его действия зависят от конфигурации среды. Обычно он выводит на экран окно с информацией об исключении и завершает текущий процесс. Системные исключения автоматически генерируются С# -системой динамического управления.
- Чтобы сгенерировать исключение вручную, используется ключевое слово throw.
- Любой код, который должен быть обязательно выполнен при выходе из try -блока, помещается в блок finally.
Отсутствовать могут либо блоки саtch, либо блок finallу, но не оба одновременно.
Итак, ядром обработки исключений являются блоки try и catch. Эти ключевые слова работают «в одной связке»; формат записи try/catch -блоков обработки исключений имеет следующий вид:
try {
// Блок кода, подлежащий проверке на наличие ошибок.
}
catch (Тип искл1 объект искл) {
// Обработчик для исключения Тип искл1
}
catch (Тип искл21 объект искл) {
// Обработчик для исключения Тип искл2
}
Здесь Тип искл – это тип сгенерированного исключения. После «выброса» исключение перехватывается соответствующей инструкцией catch, которая его обрабатывает. Как видно из формата записи try/catch- блоков, с try -блоком может быть связана не одна, а несколько catch -инструкций. Их последовательность должна располагаться непосредственно за блоком try. Блоки саtch просматриваются в том порядке, в котором они записаны. Какой именно из них будет выполнен, определит тип исключения. Другими словами, будет выполнена та catch -инструкция, тип исключения которой совпадает с типом сгенерированного исключения (а все остальные будут проигнорированы). После перехвата исключения параметр объект искл, если он присутствует,примет значение Тип искл.
Если обработчику исключения не нужен доступ к объекту исключения, то параметр объект искл можно опустить. Если исключение не генерируется, то try -блок завершается нормально, и все его catch -инструкции игнорируются. В таблице 10.1 представлены наиболее часто используемые исключения, определенные в пространстве имен System.
Таблица 10.1 – Наиболее часто используемые исключения
Исключение | Значение |
ArrayTypeMismatchException | Тип сохраняемого значения несовместим с типом массива |
DivideByZeroException | Попытка деления на нуль |
IndexOutOfRangeException | Индекс массива оказался вне диапазона |
InvalidCastException | Неверно выполнено динамическое приведение типов |
OutofMemoryException | Недостаточный объем свободной памяти |
OverflowException | Имеет место арифметическое переполнение |
NullReferenceException | Попытка использовать нулевую ссылку |
StackoverflowException | Переполнение стека |
Иногда требуется перехватывать все исключения, независимо от их типа. Для этого используется catch -инструкция без параметров. В этом случае создается обработчик, который используется, чтобы программа гарантированно обработала все исключения.
В любом случае, произошло исключение или нет, управление передается в блок завершения finally (если он существует), а затем – первому оператору, находящемуся непосредственно за оператором try. В завершающем блоке обычно записываются операторы, которые необходимо выполнить независимо от того, возникло исключение или нет, например, закрытие файлов, с которыми выполнялась работа в контролируемом блоке, или вывод информации.