ГЛАВА 13 Обработка исключительных ситуаций

Исключительная ситуация , или просто исключение, происходит во время выполнения. Используя подсистему обработки исключительных ситуаций в С#, можно обрабатывать структурированным и контролируемым образом ошибки, возникающие при выполнении программы. Главное преимущество обработки исключительных ситуаций заключается в том, что она позволяет автоматизировать получение большей части кода, который раньше приходилось вводить в любую крупную программу вручную для обработки ошибок. Так, если программа написана на языке программирования без обработки исключительных ситуаций, то при неудачном выполнении методов приходится возвращать коды ошибок, которые необходимо проверять вручную при каждом вызове метода.

Это не только трудоемкий, но и чреватый ошибками процесс. Обработка исключительных ситуаций рационализирует весь процесс обработки ошибок, позволяя определить в программе блок кода, называемый обработчиком исключений и выполняющийся автоматически, когда возникает ошибка. Это избавляет от необходимости проверять вручную, насколько удачно или неудачно завершилась конкретная операция либо вызов метода. Если возникнет ошибка, она будет обработана соответствующим образом обработчиком ошибок.

Обработка исключительных ситуаций важна еще и потому, что в C# определены стандартные исключения для типичных программных ошибок, например деление на нуль или выход индекса за границы массива. Для реагирования на подобные ошибки в программе должно быть организовано отслеживание и обработка соответствующих

исключительных ситуаций. Ведь в конечном счете для успешного программирования на C# необходимо научиться умело пользоваться подсистемой обработки исключительных ситуаций.

Класс System. Exception

В C# исключения представлены в виде классов. Все классы исключений должны быть производными от встроенного в C# класса Exception, являющегося частью пространства имен System. Следовательно, все исключения являются подклассами класса Exception.

К числу самых важных подклассов Exception относится класс SystemException. Именно от этого класса являются производными все исключения, генерируемые исполняющей системой C# (т.е. системой CLR). Класс SystemException ничего не добавляет к классу Exception, а просто определяет вершину иерархии стандартных исключений.

В среде .NET Framework определено несколько встроенных исключений, являющихся производными от класса SystemException. Например, при попытке выполнить деление на нуль генерируется исключение DivideByZeroException. Как будет показано далее в этой главе, в C# можно создавать собственные классы исключений, производные от класса Exception.

Основы обработки исключительных ситуаций

Обработка исключительных ситуаций в C# организуется с помощью четырех ключевых слов: try, catch, throw и finally. Они образуют взаимосвязанную подсистему, в которой применение одного из ключевых слов подразумевает применение другого. На протяжении всей этой главы назначение и применение каждого из упомянутых выше ключевых слов будет рассмотрено во всех подробностях. Но прежде необходимо дать общее представление о роли каждого из них в обработке исключительных ситуаций. Поэтому ниже кратко описан принцип их действия.

Операторы программы, которые требуется контролировать на появление исключений, заключаются в блок try. Если внутри блока try возникает исключительная ситуация, генерируется исключение. Это исключение может быть перехвачено и обработано каким-нибудь рациональным способом в коде программы с помощью оператора, обозначаемого ключевым словом catch. Исключения, возникающие на уровне системы, генерируются исполняющей системой автоматически. А для генерирования исключений вручную служит ключевое слово throw. Любой код, который должен быть непременно выполнен после выхода из блока try, помещается в блок finally.

Применение пары ключевых слов try и catch

Основу обработки исключительных ситуаций в C# составляет пара ключевых слов try и catch. Эти ключевые слова действуют совместно и не могут быть использованы порознь. Ниже приведена общая форма определения блоков try/catch для обработки исключительных ситуаций:

try {

// Блок кода, проверяемый на наличие ошибок.

} catch (ExcepTypel exOb) {

// Обработчик исключения типа ExcepTypel.}

catch ( ЕхсерТуре2 exOb) {

// Обработчик исключения типа ЕхсерТуре2. }

где ЕхсерТуре — это тип возникающей исключительной ситуации. Когда исключение генерируется оператором try, оно перехватывается составляющим ему пару оператором catch, который затем обрабатывает это исключение. В зависимости от типа исключения выполняется и соответствующий оператор catch. Так, если типы генерируемого исключения и того, что указывается в операторе catch, совпадают, то выполняется именно этот оператор, а все остальные пропускаются. Когда исключение перехватывается, переменная исключения exOb получает свое значение.

На самом деле указывать переменную exOb необязательно. Так, ее необязательно указывать, если обработчику исключений не требуется доступ к объекту исключения, что бывает довольно часто. Для обработки исключения достаточно и его типа. Именно поэтому во многих примерах программ, приведенных в этой главе, переменная exOb опускается.

Следует, однако, иметь в виду, что если исключение не генерируется, то блок оператора try завершается как обычно, и все его операторы catch пропускаются. Выполнение программы возобновляется с первого оператора, следующего после завершающего оператора catch. Таким образом, оператор catch выполняется лишь в том случае, если генерируется исключение.

Простой пример обработки исключительной ситуации

Рассмотрим простой пример, демонстрирующий отслеживание и перехватывание исключения. Как вам должно быть уже известно, попытка индексировать массив за его границами приводит к ошибке. Когда возникает подобная ошибка, система CLR генерирует исключение IndexOutOfRangeException, которое определено как стандартное для среды .NET Framework. В приведенной ниже программе такое исключение генерируется намеренно и затем перехватывается.

// Продемонстрировать обработку исключительной ситуации.

Using System;

class ExcDemol {

static void Main() {

int[] nums = new int [4];

try {

Console.WriteLine("До генерирования исключения.");

// Сгенерировать исключение в связи с выходом индекса за границы массива.

for(int i=0; i < 10; i++) {

nums[i] = i;

Console.WriteLine("nums[{0}]: {1}", i, nums[i]);

}

Console.WriteLine("He подлежит выводу");

}

catch (IndexOutOfRangeException) {

// Перехватить исключение.

Console.WriteLine("Индекс вышел за границы массива!");

}

Console.WriteLine("После блока перехвата исключения.");

}

}