Полное руководство. С# 4.0 - Шилдт Герберт
Шрифт:
Интервал:
Закладка:
В этом примере программы ошибки из-за деления на нуль обрабатываются локально в методе GenException(), но ошибка выхода за границы массива генерируетсяповторно. В данном случае исключение IndexOutOfRangeException обрабатываетсяв методе Main().Использование блока finally
Иногда требуется определить кодовый блок, который будет выполняться после выхода из блока try/catch. В частности, исключительная ситуация может возникнутьв связи с ошибкой, приводящей к преждевременному возврату из текущего метода.Но в этом методе мог быть открыт файл, который нужно закрыть, или же установленосетевое соединение, требующее разрывания. Подобные ситуации нередки в программировании, и поэтому для их разрешения в C# предусмотрен удобный способ: воспользоваться блоком finally.
Для того чтобы указать кодовый блок, который должен выполняться после блокаtry/catch, достаточно вставить блок finally в конце последовательности операторовtry/catch. Ниже приведена общая форма совместного использования блоков try/catch и finally.try { // Блок кода, предназначенный для обработки ошибок.}catch (ExcepType1 exOb) { // Обработчик исключения типа ExcepType1.}catch (ExcepType2 ехОb) { // Обработчик исключения типа ЕхсерТуре2.}finally { // Код завершения обработки исключений.}
Блок finally будет выполняться всякий раз, когда происходит выход из блока try/catch, независимо от причин, которые к этому привели. Это означает, что если блокtry завершается нормально или по причине исключения, то последним выполняетсякод, определяемый в блоке finally. Блок finally выполняется и в том случае, еслилюбой код в блоке try или в связанных с ним блоках catch приводит к возврату изметода.
Ниже приведен пример применения блока finally.// Использовать блок finally.using System;class UseFinally { 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 { static void Main() { for(int i=0; i < 3; i++) { UseFinally.GenException(i); Console.WriteLine(); } }}
Вот к какому результату приводит выполнение этой программы.Получить 0Делить на нуль нельзяПосле выхода из блока try.Получить 1Совпадающий элемент не найден.После выхода из блока try.Получить 2После выхода из блока try.
Как следует из приведенного выше результата, блок finally выполняется независимо от причины выхода из блока try.
И еще одно замечание: с точки зрения синтаксиса блок finally следует после блокаtry, и формально блоки catch для этого не требуются. Следовательно, блок finallyможно ввести непосредственно после блока try, опустив блоки catch. В этом случаеблок finally начнет выполняться сразу же после выхода из блока try, но исключенияобрабатываться не будут.Подробное рассмотрение класса Exception
В приведенных выше примерах исключения только перехватывались, но никакойсущественной обработке они не подвергались. Как пояснялось выше, в оператореcatch допускается указывать тип и переменную исключения. Переменная получаетссылку на объект исключения. Во всех исключениях поддерживаются члены, определенные в классе Exception, поскольку все исключения являются производными отэтого класса. В этом разделе будет рассмотрен ряд наиболее полезных членов и конструкторов класса Exception и приведены конкретные примеры использования переменной исключения.
В классе Exception определяется ряд свойств. К числу самых интересных относятся три свойства: Message, StackTrace и TargetSite. Все эти свойства доступнытолько для чтения. Свойство Message содержит символьную строку, описывающуюхарактер ошибки; свойство StackTrace — строку с вызовами стека, приведшими к исключительной ситуации, а свойство TargetSite получает объект, обозначающий метод, сгенерировавший исключение.
Кроме того, в классе Exception определяется ряд методов. Чаще всего приходитсяпользоваться методом ToString(), возвращающим символьную строку с описаниемисключения. Этот метод автоматически вызывается, например, при отображении исключения с помощью метода WriteLine().
Применение всех трех упомянутых выше свойств и метода из класса Exceptionдемонстрируется в приведенном ниже примере программы.// Использовать члены класса Exception.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 UseExcept { static void Main() { try { ExcTest.GenException(); } catch (IndexOutOfRangeException exc) { Console.WriteLine("Стандартное сообщение таково: "); Console.WriteLine(exc); // вызвать метод ToString() Console.WriteLine("Свойство StackTrace: " + exc.StackTrace); Console.WriteLine("Свойство Message: " + exc.Message); Console.WriteLine("Свойство TargetSite: " + exc.TargetSite); } Console.WriteLine("После блока перехвата исключения."); }}
При выполнении этой программы получается следующий результат.До генерирования исключения.nums[0]: 0nums[1]: 1nums[2]: 2nums[3]: 3Стандартное сообщение таково: System.IndexOutOfRangeException: Индекс находилсявне границ массива. в ExcTest.genException() в <имя_файла>:строка 15 в UseExcept.Main() в <имя_файла>:строка 29Свойство StackTrace:в ExcTest.genException() в <имя_файла>:строка 15 в UseExcept.Main()в <имя_файла>:строка 29Свойство Message: Индекс находился вне границ массива.Свойство TargetSite: Void genException()После блока перехвата исключения.
В классе Exception определяются четыре следующих конструктора.public Exception()public Exception(string сообщение)public Exception(string сообщение, Exception внутреннее_исключение)protected Exception(System.Runtime.Serialization.SerializationInfo информация, System.Runtime.Serialization.StreamingContext контекст)
Первый конструктор используется по умолчанию. Во втором конструкторе указывается строка сообщение, связанная со свойством Message, которое имеет отношение к генерируемому исключению. В третьем конструкторе указывается так называемое внутреннее исключение. Этот конструктор используется в том случае, когдаодно исключение порождает другое, причем внутреннее_исключение обозначаетпервое исключение, которое будет пустым, если внутреннее исключение отсутствует.(Если внутреннее исключение присутствует, то оно может быть получено из свойстваInnerException, определяемого в классе Exception.) И последний конструктор обрабатывает исключения, происходящие дистанционно, и поэтому требует десериализации.
Следует также заметить, что в четвертом конструкторе класса Exception типыSerializationInfo и StreamingContext относятся к пространству имен System.Runtime.Serialization.Наиболее часто используемые исключения
В пространстве имен System определено несколько стандартных, встроенных исключений. Все эти исключения являются производными от класса SystemException,поскольку они генерируются системой CLR при появлении ошибки во время выполнения. В табл. 13.1 перечислены некоторые наиболее часто используемые стандартныеисключения.
Таблица 13.1. Наиболее часто используемые исключения, определенные в пространстве имен SystemИсключениеЗначениеArrayTypeMismatchExceptionТип сохраняемого значения несовместим с типом массиваDivideByZeroExceptionПопытка деления на нульIndexOutOfRangeExceptionИндекс оказался за границами массиваInvalidCastExceptionНеверно выполнено динамическое приведение типовOutOfMemoryExceptionНедостаточно свободной памяти для дальнейшего выполнения программы. Это исключение может быть, например, сгенерировано, если для создания объекта с помощью оператора new не хватает памятиOverflowExceptionПроизошло арифметическое переполнениеNullReferenceExceptionПопытка использовать пустую ссылку, т.е. ссылку, которая не указывает ни на один из объектов