C# 4.0 полное руководство - 2011 - Герберт Шилдт
Шрифт:
Интервал:
Закладка:
Console.WriteLine("He подлежит выводу");
}
catch (IndexOutOfRangeException) {
// Перехватить исключение.
Console.WriteLine("Индекс вышел за границы массива!");
}
Console.WriteLine("После блока перехвата исключения.");
}
}
При выполнении этой программы получается следующий результат.
До генерирования исключения.
nums[0]: О
nums[1]: 1
nums[2]: 2
nums[3]: 3
Индекс вышел за границы массива!
После блока перехвата исключения.
В данном примере массив nums типа int состоит из четырех элементов. Но в цикле for предпринимается попытка проиндексировать этот массив от 0 до 9, что и приводит к появлению исключения IndexOutOfRangeException, когда происходит обращение к элементу массива по индексу 4.
Несмотря на всю свою краткость, приведенный выше пример наглядно демонстрирует ряд основных моментов процесса обработки исключительных ситуаций. Во-первых, код, который требуется контролировать на наличие ошибок, содержится в блоке try. Во-вторых, когда возникает исключительная ситуация (в данном случае — при попытке проиндексировать массив nums за его границами в цикле for), в блоке try генерируется исключение, которое затем перехватывается в блоке catch. В этот момент выполнение кода в блоке try завершается и управление передается блоку catch. Это означает, что оператор catch не вызывается специально, а выполнение кода переходит к нему автоматически. Следовательно, оператор, содержащий метод WriteLine () и следующий непосредственно за циклом for, где происходит выход индекса за границы массива, вообще не выполняется. А в задачу обработчика исключений входит исправление ошибки, приведшей к исключительной ситуации, чтобы продолжить выполнение программы в нормальном режиме.
Обратите внимание на то, что в операторе catch указан только тип исключения (в данном случае — IndexOutOfRangeException), а переменная исключения отсутствует. Как упоминалось ранее, переменную исключения требуется указывать лишь в том случае, если требуется доступ к объекту исключения. В ряде случаев значение объекта исключения может быть использовано обработчиком исключений для получения дополнительной информации о самой ошибке, но зачастую для обработки исключительной ситуации достаточно просто знать, что она произошла. Поэтому переменная исключения нередко отсутствует в обработчиках исключений, как в рассматриваемом здесь примере.
Как пояснялось ранее, если исключение не генерируется в блоке try, то блок catch не выполняется, а управление программой передается оператору, следующему после блока catch. Для того чтобы убедиться в этом, замените в предыдущем примере программы строку кода
for(int i=0; i < 10; i++) {
на строку
for(int i=0; i < nums.Length; i++) {
Теперь индексирование массива не выходит за его границы в цикле for. Следовательно, никакого исключения не генерируется и блок catch не выполняется.
Второй пример обработки исключительной ситуации
Следует особо подчеркнуть, что весь код, выполняемый в блоке try, контролируется на предмет исключительных ситуаций, в том числе и тех, которые могут возникнуть в результате вызойа метода из самого блока try. Исключение, генерируемое методом в блоке try, может быть перехвачено в том же блоке, если, конечно, этого не будет сделано в самом методе.
В качестве еще одного примера рассмотрим следующую программу, где блок try помещается в методе Main (). Из этого блока вызывается метод GenException (), в котором и генерируется исключение IndexOutOfRangeException. Это исключение не перехватывается методом GenException (). Но поскольку метод GenException () вызывается из блока try в методе Main (), то исключение перехватывается в блоке catch, связанном непосредственно с этим блоком try.
/* Исключение может быть сгенерировано одним методом и перехвачено другим. */
using System;
class ExcTest {
// Сгенерировать исключение, public static void GenException() {
int[] nums = new int [4];
Console.WriteLine("До генерирования исключения.");
// Сгенерировать исключение в связи с выходом индекса за границы массива.
for(int i=0; i < 10; i++) {
nums[i] = i;
Console.WriteLine("nums[{0}]: {1}", i, nums[i]);
}
Console.WriteLine("He подлежит выводу");
}
}
class ExcDemo2 {
static void Main() {
try {
ExcTest.GenException() ;
}
catch (IndexOutOfRangeException) {
// Перехватить исключение. 9
Console.WriteLine("Индекс вышел за границы массива!");
}
Console.WriteLine("После блока перехвата исключения.");
}
}
Выполнение этой программы дает такой же результат, как и в предыдущем примере.
До генерирования исключения.
nums[0]: О
nums[1]: 1
nums[2]: 2
nums[3]: 3
Индекс вышел за границы массива!
После блока перехвата исключения.
Как пояснялось выше, метод GenException () вызывается из блока try, и поэтому генерируемое им исключение перехватывается не в нем, а в блоке catch внутри метода Main (). А если бы исключение перехватывалось в методе GenException (), оно не было бы вообще передано обратно методу Main ().
Последствия неперехвата исключений
Перехват одного из стандартных исключений, как в приведенных выше примерах, дает еще одно преимущество: он исключает аварийное завершение программы. Как только исключение будет сгенерировано, оно должно быть перехвачено каким-то фрагментом кода в определенном месте программы. Вообще говоря, если исключение не перехватывается в программе, то оно будет перехвачено исполняющей системой. Но дело в том, что исполняющая система выдаст сообщение об ошибке и прервет выполнение программы. Так, в приведенном ниже примере программы исключение в связи с выходом индекса за границы массива не перехватывается.
// Предоставить исполняющей системе C# возможность самой обрабатывать ошибки.
using System;
class NotHandled { static void Main() {
int[] nums = new int[4];
Console.WriteLine("До генерирования исключения.");
// Сгенерировать исключение в связи с выходом индекса за границы массива, for (int i=0; i < 10; i++) {
nums[i] = i;
Console.WriteLine("nums[{0}] : {1}", i, nums[i]);
Когда возникает ошибка индексирования массива, выполнение программы прерывается и выдается следующее сообщение об ошибке.
Необработанное исключение: System.IndexOutOfRangeException:
Индекс находился вне границ массива, в NotHandled.Main() в <имя_файла>:строка 16
Это сообщение уведомляет об обнаружении в методе NotHandled. Main () необработанного исключения типа System. IndexOutOfRangeException, которое связано с выходом индекса за границы массива.
Такие сообщения об ошибках полезны для отладки программы, но, по меньше мере, нежелательны при ее использовании на практике! Именно поэтому так важно организовать обработку исключительных ситуаций в самой программе.
Как упоминалось ранее, тип генерируемого исключения должен соответствовать типу, указанному в операторе catch. В противном случае исключение не будет перехвачено. Например, в приведенной ниже программе предпринимается попытка перехватить ошибку нарушения границ массива в блоке catch, реагирующем на исключение DivideByZeroException, связанное с делением на нуль и являющееся еще одним стандартным исключением. Когда индексирование массива выходит за его границы, генерируется исключение IndexOutOfRangeException, но оно не будет перехвачено блоком catch, что приведет к аварийному завершению программы.
// Не сработает!
using System;
class ExcTypeMismatch { static void Main() {
int[] nums = new int [4];
try {
Console.WriteLine("До генерирования исключения.");