Полное руководство. С# 4.0 - Шилдт Герберт
Шрифт:
Интервал:
Закладка:
Обработка исключительных ситуаций важна еще и потому, что в С# определены стандартные исключения длятипичных программных ошибок, например деление нануль или выход индекса за границы массива. Для реагирования на подобные ошибки в программе должно бытьорганизовано отслеживание и обработка соответствующихисключительных ситуаций. Ведь в конечном счете для успешного программированияна 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 (ExcepType1 exOb) { // Обработчик исключения типа ExcepTypel.}catch (ExcepType2 exOb) { // Обработчик исключения типа ExcepType2.}
где ЕхсерТуре — это тип возникающей исключительной ситуации. Когда исключениегенерируется оператором try, оно перехватывается составляющим ему пару оператором catch, который затем обрабатывает это исключение. В зависимости от типаисключения выполняется и соответствующий оператор catch. Так, если типы генерируемого исключения и того, что указывается в операторе catch, совпадают, то выполняется именно этот оператор, а все остальные пропускаются. Когда исключениеперехватывается, переменная исключения exOb получает свое значение.
На самом деле указывать переменную ехОb необязательно. Так, ее необязательноуказывать, если обработчику исключений не требуется доступ к объекту исключения,что бывает довольно часто. Для обработки исключения достаточно и его типа. Именнопоэтому во многих примерах программ, приведенных в этой главе, переменная ехОbопускается.
Следует, однако, иметь в виду, что если исключение не генерируется, то блок оператора 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("После блока перехвата исключения."); }}
При выполнении этой программы получается следующий результат.До генерирования исключения.nums[0]: 0nums[1]: 1nums[2]: 2nums[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 не выполняется.Второй пример обработки исключительной ситуации