Г. Шилдт - С# 3.0 Полное руководство. 2010 (1160798), страница 78
Текст из файла (страница 78)
Такое может, в частности, произойти при неконтролируемом выполнении рекурсивного метода. В этом случае стек рано или поздно переполняется, но исключение Бгас)сбчегг1ойнхсерс1оп не перехватывается программой, и поэтому ее выполнение прерывается преждевременно. 408 Часть (. Язык С№ Получение производных классов исключений Несмотря на то что встроенные исключения охватывают наиболее распространенные программные ошибки, обработка исключительных ситуаций в С№ не ограничивается только этими ошибками. В действительности одна из сильных сторон принятого в С№ подхода к обработке исключительных ситуаций состоит в том, что в этом языке допускается использовать исключения, определяемые пользователем, т.е.
тем, кто программирует на С№. В частности, такие специальные исключения можно использовать для обработки ошибок в собственном коде, а создаются они очень просто. Для этого достаточно определить класс, производный от класса Ехсерг1оп. В таких классах совсем не обязательно что-то реализовывать — одного только их существования в системе типов уже достаточно, чтобы использовать их в качестве исключений. На заметку.' В проилом специальные исключения создавались как производные от класса йрр11сатгоо.
Ексерт гоп, поскольку Ьта иерархия классов была первоначально эареэервирована для исключений прикладиого характера. Ио теперь корпорация М(стого/г не рекомендует этого делать, а вместо этого получать исключения, производные от кэасса Ексерг1оп. Именно по этой причине данный подход и рассматривается в настоящей книге. Создаваемые пользователем классы будут автоматически получать свойства и методы, определенные в классе ехсерг1оп и доступные для них. Разумеется, любой из этих членов класса Ехсерсйоп можно переопределить в создаваемых классах исключений. Когда создается собственный класс исключений, то, как правило, желательно, чтобы в нем поддерживались все конструкторы, определенные в классе Ехсерсйоп.
В простых специальных классах исключений этого нетрудно добиться, поскольку для этого достаточно передать подходящие аргументы соответствующему конструктору класса Ехсерг1оп, используя ключевое слово Ьазе. Но формально нужно предоставить только те конструкторы, которые фактически используются в программе.
Рассмотрим пример программы, в которой используется исключение специального типа. Напомним, что в конце главы 10 был разработан класс еапдейггау, поддерживающий одномерные массивы, в которых начальный и конечный индексы определяются пользователем. Так, например, вполне допустимым считается массив, индексируемый в пределах от -5 до 27. Если же индекс выходил за границы массива, то для обработки этой ошибки в классе капдейггау была определена специальная переменная.
Такая переменная устанавливалась и проверялась после каждой операции обращения к массиву в коде, использовавшем класс еапдейггау. Безусловно, такой подход к обработке ошибок неуклюж и чреват дополнительными ошибками. В приведенном ниже улучшенном варианте класса еапдейггау обработка ошибок нарушения границ массива выполняется более изящным и надежным способом с помощью специально генерируемого исключения. // Использовать специальное исключение ддя обработки // ошибок при обращении к иассизу класса Напдейггау. цв1пд Зуэсеш; // создать исключение для класса вапдейггау.
с1авз Напдейггаукхсерсгоп: Ехсерсьоп ( /* Реализовать все конструкторы кла~са Ехсерс1оп. Такие Глава 13. Обработка исключительных ситуаций 409 конструкторы просто реализуют конструктор базового класса. А поскольку класс исключения ВапдеАггауехсерс1оп ничего не добавляет к классу Ехсеркгоп, то никаких дополнительных действий не требуется.
*/ риЬ1гс ВапдеАггауЕхсеркгоп(): Ьаяе() ( риЫгс ВапдеАггауЕхсерС1оп(якг1пд якг) : Ьаяе (ягг) ( ) риЫгс ВапдеАггауЕхсеркгоп( згггпд ягг, Ехсеркгоп гппег) к Ьаяе(вкг, 1ппег) ( ) ргоиескеб ВапделггауЕхсергаоп( Вузкеш.аипС1ше.5ег1а11яаС1оп.5ег1а11яаггоптпко яг, 5узкеш.нипС1ше.5ег1а11яаС1оп.ВСгеаш1пдсопиехС яс] Ьаве(я)., яс) ( ) // переопределить метод то5сг1пд() для класса // исключения ВапдеАггауЕхсерггоп. риЫгс очегг1бе ясг1пд Тоегг1пд() ( гекигп Мевяаде; ) // Улучшенный вариант класса Вапделггау.
с1азз Вапделггау ( // Эакрытые данные. хпС[] ат // ссылка на базовый массив 1ЬС 1онегВоипбт // наименьший индекс гпС иррегВоипбт // наибольший индекс // Автоматически реализуемое и доступное только для // чтения свойство ЬепдСЬ. риЫгс гпС Ьепдгп ( дегт ргачасе зес) ) // Построить массив по заданному размеру риЫ1с Еапделггау(хпк 1он, 1пС Ьгдп) ( Ьхдп++) хт(ЬгдЬ <= 1он) ( СЬгон пен ВапделггауЕхсеркаоп("Нижний индекс не меньше верхнего."); ) а = пен гпс[ЫПЬ вЂ” 1он]; ЬепдСЬ Ыдп — 1онт 1онегВоипб = 1онт иррегВоипб = — Ьгдпт ) // Это индексатор для класса Вапделггау.
риЫгс кпг СЬ1я(гпг гпбех] [ // Это аксессор дес. дес ( 11(он(1пбех)) ( гесигп а(хпбех - 1онегВоипб]) ) е1яе ( СЬгон пен ВапделггауЕхсерС1оп(убшибка нарушения границ."); 410 Часть ). )(эык С() // Это аксессор аег. вес ( 11(о)с(1пбех)) ( а[апбех — 1онегВоцпб] = ча1це; е1зе вагон пен ВапдейггауЕхсерг1оп("Ошибка нарушения границ."); ) ) // Возвратить логическое значение Ггце, если // индекс находится в установленных границах.
ргачасе Ьоо1 ой(1пс 1пбех) ( 15(1пбех >= 1онегВоцпб а Ьпбех <= цррегВоцпб) гегцгп ггце) гегцгп га1веь ) // Продемонстрировать применение массива с произвольно // задаваемыми пределами индексирования. с1азв Вапдейггаубешо ( всасас чоьб Маап() ( сгу ( йапдейггау га пен КапдеАггау(-5, 5)) йапдейггау га2 = пен йапдейггау(1, 10); // использовать объект га в качестве массива. Сопао1е.нгасеЬЬпе("Длина массива га: " + га.Ьепдсй); 1ог(апс 1 = -5) 1 <= 5; 1++) га(1) = 1) Сопво1е.иг1се("Содержимое массива га: ")) Вот(гпг 1 = -5; 1 <= 5; 1++) сопзо1е.иг1ге(та[1] + " ") ) Сопво1е. Иг1сеЬ1пе ("1п" ); // Использовать объект га2 в качестве массива. Сопза1е.нгасеЬ1пе("Длина массива га2: " + га2.Ьепдгп) Вот(апс 1 = 1; 1 <= 10; 1++) га2(3] = 1," Сопво1е.иг1се("Длина массива га2: ")) Вот(1пг 1 = 1; 1 <= 10; 1ьь) Сопзо1е.нгасе(га2(1] + " "): сопзо1е.игагеьапе ("1п" ) 2 ) сатен (йапдеАггауЕхсерсаоп ехс) ( Сопво1е.игасеЬЬпе(ехс)) ) Глава (3, Обработка исключительных ситуаций 411 // А теперь продемонстрировать обработку // некоторых ошибок.
Сопво1е.игхсевапе("Сгенерировать ошибки нарушения границ."); // Использовать неверно заданный конструктор. ггу ( аапдейггау гаЗ = пен Напдехггау(100, -10)т // Ошибка! ) сагсп (ВапдеаггауЕхсерсхоп ехс) ( Сопво1е.иг1сеъхпе(ехс)т ) // Использовать неверно заданный индекс. ггу ( напдеаггау гаЗ = пеы капдейггау(-2, 2)т Гог(тпг 1 -2) 1 <= 2) 144) гаЗ(х! = 17 Сопзо1е.игаге("Содержимое массива гаЗ: ")т лог(лпг 1 = -2) 1 <= 107 1++) // сгенерировать ошибку нарушения границ Сопво1е.иглге(гаЗ(1.) + " ")т ) салоп (Вапдеаггауехсергхоп ехс) ( Сопзо1е.иг1сеъкпе(ехс)) ) ) При выполнении этой программы получается следующий результат: длина массива га: 11 Содержимое массива га: -5 -4 -3 -2 -1 0 1 2 3 4 5 длина массива га2: 10 Содержимое массива га2: 1 2 3 4 5 б 7 В 9 10 Сгенерировать ошибки нарушения границ.
Нижний индекс не меньше верхнего. Содержимое массива гаЗ: -2 -1 0 1 2 Ошибка нарушения границ. Когда возникает ошибка нарушения границ массива класса напдейггау, генерируется объект типа папдейггаукхсерсйоп. В классе Напдейггау зто может произойти в трех следующих местах; в аксессоре дес индексатора, в аксессоре зес индексатора и в конструкторе класса Папдейггау.
Для перехвата этих исключений подразумевается, что объекты типа Напдейггау должны быть сконструированы и доступны из блока сгу, что и продемонстрировано в приведенной выше программе. Используя специальное исключение для сообщения об ошибках, класс напдейггау теперь действует как один из встроенных в С№ типов данных и поэтому может быть полностью интегрирован в механизм обработки ошибок, обнаруживаемых в программе. Обратите внимание на то, что в теле конструкторов класса исключения капдейггау Ехсергйоп отсутствуют какие-либо операторы, но вместо этого они просто передают 412 Часть (.
Язык С(( свои аргументы классу Ехсерггсп, используя ключевое слово Ьазе. Как пояснялось раисе, в тех случаях, когда производный класс исключений ие дополняет функции базового класса, весь процесс создания исключений можно поручить коиструкторам класса ехсерсгоп. Ведь производный класс исключений совсем ие обязательно должен чем-то дополнять функции, наследуемые от класса Ехсерг1оп. Прежде чем переходить к дальнейшему чтению, попробуйте немного поэксперимеитировать с приведенной выше программой.