Console.WriteLine(

Console.WriteLine(

"Произошло некоторое исключение.");

}}}}

Вот как выглядят результаты выполнения этой программы:

 

4/2

равно 2

Произошло некоторое исключение.

16/4 равно 4

32/4 равно 8

Произошло некоторое исключение.

128/8 равно 16

Произошло некоторое исключение.

Произошло некоторое исключение.

 

7.5 Вложение try-блоков

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

usingSystem; // Использование вложенного try-блока,

class NestTrys {

public static void Main() {

// Здесь массив numer длиннее массива denom.

int[] numer = { 4, 8, 16, 32, 64, 128, 256, 512 };

int[] denom = { 2, 0, 4, 4, 0, 8 };

try { // Внешний try-блок.

for(int i=0; i < numer.Length; i++) {

try { // Вложенный try-блок

Console.WriteLine(numer[i] + " / " +denom[i] + " равно " +

numer[i]/denom[i]);

}

catch (DivideByZeroException) {// Перехватываем исключение

Console.WriteLine("Нанульделитьнельзя!");

}}}

catch (IndexOutOfRangeException) {

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

Console.WriteLine("Нет соответствующего элемента.");

"Неисправимая ошибка — программа завершена.");

}}}

Вот результаты выполнения этой программы:

4/2

равно 2

На нуль делить нельзя!

16/4 равно 4

32/4 равно 8

На нуль делить нельзя!

128/8 равно 16

Нет соответствующего элемента.

Неисправимая ошибка — программа завершена.

 

Многие программисты используют внешний try-блок для перехвата самых серьезных ошибок, позволяя внутренним try-блокам обрабатывать менее опасные. Внешние try-блоки можно также использовать в качестве механизма "глобального перехвата" для обработки тех ошибок, которые не перехватываются внутренним блоком.

 

7.6 Генерирование исключений программно

Помимо генерации исключений генерируемых средствами С#, можно сгенерировать исключение программно, используя инструкцию throw. Формат ее записан таков:

throwexceptOb;

Элемент exceptOb — это объект класса исключений, производного от классаException.

Рассмотрим пример, который демонстрирует использование инструкции throw для генерирования исключения типа DivideByZeroExceptionпрограммно.

.

usingSystem; // Генерирование исключения вручную

classThrowDemo {

public static void Main() {

try {

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

throw new DivideByZeroException();

}

catch (DivideByZeroException) { // Перехватываемисключение.

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

}

Console.WriteLine("После try/catch-блока.");

}}

Результаты выполнения этой программы имеют такой вид:

 

До генерирования исключения.

Исключение перехвачено.

После try/catch-блока.

 

Объект исключения типа DivideByZeroException, создан с помощью оператора new в инструкции throw.

 

При создании объекта класса DivideByZeroExceptionиспользовался конструктор по умолчанию, но для генерирования исключений предусмотрены и другие конструкторы.

Чаще всего генерируемые исключения являются экземплярами классов исключений, создаваемых в программе.

 

7.7 Повторное генерирование исключений

Исключение, перехваченное одной catch-инструкцией, можно перегенерировать,чтобы обеспечить возможность его перехвата другой (внешней) catch-инструкцией.Самая распространенная причина для повторного генерирования исключения — позволить нескольким обработчикам получить доступ к исключению. Например, возможна такая ситуация, что один обработчик исключений управляет одним аспектомисключения, а второй — другим. Чтобы повторно сгенерировать исключение, достаточно использовать ключевое слово throw, не указывая исключения. Другими словами, используйте следующую форму инструкции throw,

throw;

При повторном генерировании исключения оно не будет повторноперехватываться той же catch-инструкцией, а передается следующей catch-инструкции.

 

using System;

class Rethrow {

public static void genException()

{ / / Здесьмассивnumerдлиннеемассиваdenom.

in t[] numer = { 4, 8, 16, 32, 64, 128, 256, 512 };

in t[] denom = { 2 , 0 , 4, 4, 0 , 8 };

for(int i=0; i<numer.Length; i++){

try {

Console.WriteLine(numer[i] + " / " + denom[i] + " равно " + numer[l]/denom[i]);

}

catch (DivideByZeroException) {// Перехватываемисключение.

Console.WriteLine("Делитьнанульнельзя!")

}

catch (IndexOutOfRangeException) { // Перехватываемисключение.

Console.WriteLine("Нетсоответствующегоэлемента.")

throw; // Генерируемисключениеповторно.

}}}}

class RethrowDemo {

public static void Main() {

try { Rethrow.genException(); }

catch(IndexOutOfRangeException) {

// Перехватываем повторно сгенерированное исключение.

Console.WriteLine("Неисправимая ошибка —"программа завершена.");

}}}

В этой программе ошибки деления на нуль обрабатываются локально (по месту),т.е. в самом методе genException (), но ошибка нарушения границ массива генерируется повторно. В данном случае исключение типа IndexOutOfRangeException обрабатывается функцией Main().

 

7.8 Использование блока finally

Иногда возникает потребность определить программный блок, который долженвыполняться по выходу из 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-инструкций определены внутри метода.

Вот пример использования блока finally:

using System;

class UseFmally {

public static void genException(int what) {

int t;

int[] nums = new int[2];

Console.WriteLine("Получаем " + what);

try {

switch(what) {

case 0:

t = 10 / what; // Генерируемошибку

// деления на нуль,

break;

case 1:

nums[4] = 4 ; // Генерируем ошибку

// индексирования массива.

break;

case 2:

return; // Возвратиз try-блока.

}}

catch (DivideByZeroException) {

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

Console.WriteLine("Нанульделитьнельзя!");

return; // Возврат из catch-блока.

}

catch (IndexOutOfRangeException) {

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

Console.WriteLine("Нет соответствующего элемента.");

}

finally {

Console.WriteLine("По окончании try-блока.");

}}}

class FinallyDemo {

public static void Main() {

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

UseFinally.genException(i);

Console.WriteLine();

}}}

Вот какие результаты получены при выполнении этой программы:

Получаем 0

На нуль делить нельзя!

По окончании try-блока.

Получаем 1

Нет соответствующего элемента.

По окончании try-блока.

Получаем 2

По окончании try-блока.

Как подтверждают результаты выполнения этой программы, независимо от итога завершения try-блока, блок finally выполняется обязательно.

7.9 Наследование классов исключений

В С# имеется возможность обрабатывать исключения, создаваемые программистом. В своих программах вы можете использовать для обработки ошибок "собственные" исключения. Для этого достаточно определить класс как производный от класса Exception. Как правило, определяемые программистом исключения, должны быть производными от класса ApplicationException, "родоначальника" иерархии, зарезервированной для исключений, связанных с прикладными программами. Созданные вами производные классы не должны ничего реализовывать, поскольку одно лишь их существование в системе типов уже позволит использовать их в качестве исключений.

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

// Создание пользовательского исключения для

// обнаружения ошибок при работе с объектами класса

// RangeArray.

using System;

// Создаем исключение для класса RangeArray.

class RangeArrayException : ApplicationException {

// Реализуемстандартныеконструкторы,

public RangeArrayException() : base() { }

public RangeArrayException(string str) : base(str) { }

// Переопределяемметод ToString()длякласса

// RangeArrayException.

public override string ToString() {

return Message;

}}

// Улучшенная версия класса RangeArray.

class RangeArray {

// Закрытые данные.

int[] а; // Ссылка на базовый массив.

intlowerBound; // Наименьший индекс.

intupperBound; // Наибольший индекс.

intlen; // Базовая переменная для свойства Length.

// Создаем массив с заданным размером,

public RangeArray(int low, int high) {

high++;

if(high <= low) {