Г. Шилдт - С#4.0 Полное руководство (1160795), страница 79
Текст из файла (страница 79)
Оба объекта класса Х создаются в методе Надо () . Первый из них (переменная р) инициализируется, а второй (переменная г() — нет. Вместо этого переменной с( присваивается пустое значение. Затем вызывается метод р. Ас(с) () с переменной с( в качестве аргумента. Но поскольку переменная г( не ссылается ни на один из объектов, то при попытке получить значение члена с(. х генерируется исключение Ып11вегегепсевхсерг1оп. Получение производных классов исключений Несмотря на то что встроенные исключения охватывают наиболее распространенные программные ошибки, обработка исключительных ситуаций в С() не ограничивается только этими ошибками.
В действительности одна из сильных сторон принятого в СЗ подхода к обработке исключительных ситуаций состоит в том, что в этом языке допускается использовать исключения, определяемые пользователем, т.е, тем, кто программирует на СЗ. В частности, такие специальные исключения можно использовать для обработки ошибок в собственном коде, а создаются они очень просто.
Для этого достаточно определить класс, производный от класса Ехсерсэоп, В таких классах совсем не обязательно что-то реализовывать — одного только их существования в системе типов уже достаточно, чтобы использовать их в качестве исключений. ПРИМЕЧАНИЕ В прошлом специальные исключения создавались как производные от класса дрр11сасдоп. Вхсерсдоп, поскольку эта иерархия классов была первоначально зарезервирована для исключений прикладного характера. Но теперь корпорация М(сгоэой не рекомендует этого делать, а вместо этого получать исключения, производные от класса Ех сер с доп. Именно по этой причине данный подход и рассматривается в настоящей книге.
Создаваемые пользователем классы будут автоматически получать свойства и методы, определенные в классе Вхсергэоп и доступные для них. Разумеется, любой из этих членов класса Ехсерсэоп можно переопределить в создаваемых классах исключений. Когда создается собственный класс исключений, то, как правило, желательно, чтобы в нем поддерживались все конструкторы, определенные в классе Вхсергдоп. В простых специальных классах исключений этого нетрудно добиться, поскольку для этого достаточно передать подходящие аргументы соответствующему конструктору класса ех серг 1 оп, используя ключевое слово ьа ве. Но формально нужно предоставить только те конструкторы, которые фактически используются в программе.
Рассмо~рим пример программы, в которой используется исключение специального типа. Напомним, что в конце главы 10 был разработан класс папоедггау, поддерживающий одномерные массивы, в которых начальный и конечный индексы определяются пользователем. Так, например, вполне допустимым считается массив, индексируемый в пределах от -5 до 27. Если же индекс выходил за границы массива, то для обработки этой ошибки в классе Ваппедггау была определена специальная переменная.
Такая переменная устанавливалась и проверялась после каждой операции обращения к массиву в коде, использовавшем класс папоедггау. Безусловно, такой подход к обработке ошибок "неуклюж" и чреват дополнительными ошибками. В приведенном ниже улучшенном варианте класса папгтедггау обработка ошибок нарушения границ Глава 13. Обработка искиочительнык ситуаций 423 массива выполняется более изящным и надежным способом с помощью специально генерируемого исключения. О Использовать специальное исключение для обработки ошибок при .обращении к массиву класса Вапдейггау. пятпд Буятешт // Создать исключение для класса Рапдейтгау. с1аяя ВапдейтгауЕхсерттоп : Ехсерттоп /* Реализовать все конструкторы класса Ехсерттоп. Такие конструкторы просто реализуют конструктор базового класса.
А поскольку класс исключения ВапдеАгтауЕхсерттоп ничего не добавляет к классу Ехсерт1оп, то никаких дополнительных действий не требуется. */ роЬ11с ВапдеАтгауЕхсерттоп() : Ьаяе() ( ) рцЬ11с ВапдейттауЕхсеря1оп (ятгтпд ятг) : Ъаяе(ятт) ( ) рцЬ1тс ВапдейттауЕхсеротоп( ятгбпд ятт, Ехсерттоп 1ппег) : Ьаяе(ятт, тппег) ( ) ртояесяеб ВапдейттауЕхсерттоп( Буятеш.ноптлше.Яегта1тяаттоп.Бегта1ттат1оп1пто я1, Буятеш.нопттше.вег1а1ттаттоп.вттеавьпдСопяехт яс) Ьаве(я1, яс) ( ) Переопределить метод Товтт1пд() для класса исключения ВапдейттауЕхсеря1оп.
рцЬ11с очетттбе ятт1пд ТоЯГт1пд() ( тегцтп Меяяадет ) ) // Улучшенный вариант класса Вапдейтгау. с1аяя Вапдейгтау ( // Закрытые данные. 1по[] а( // ссылка на базовый массив 1пт 1онетВоцпб," // наименьший индекс 1пт црретВоцпбт // наибольший индекс // Автоматически реализуемое и доступное только для чтения свойство Ьепдяь. рцЬ11с 1пт ЬепдГЬ ( детт ргбчате яетт ) Построить массив по заданному размеру рцЬ11с Вапдейттау(тпт 1он, тпя ЬлдЬ) ( ЬЬБЬ+ь; тт(иьдЬ <= 1он) ( ГЬгон пен ВапдеАтгауЕхсерттоп("Нижний индекс не меньше верхнего.") ) а = пен тпт[иьдЬ вЂ” 1он] т Ьепдяь = ЬЬБЬ вЂ” 1он( 1онегВоопб = 1онт црретВоцпб = — ЬтдЬ) ) // Зто индексатор для класса ВапдеАттау.
рцЬ11с тпт Гььв[тпт тпбех] ( 424 Часть ]. Язык С№ // Это аксессор дег. дев ( гг (ок ().пбех) ) ( гесцгп а[гпбех — 1оиегаоцпб]) ) е1ве гогом пеи ВапдеАггауЕхсерсгоп("Ошибка нарушения границ.") ) Это аксессор вел. зес ( Ьг (о)с (1пс(ех) ) ( а[годах — 1онегаоцпб] = ча1це) ) е1ве Гогом пен ВапдепггауЕхсерсгоп("Ошибка нарушения границ."); ) ) // Возвратить логическое значение Сгце, если // индекс находится в установленных границах. рг1чаое Ьоо1 оь(1по 1пбех) ( гт(1пбех >= 1онегаоцпб С 1пбех <= цррегаоцпб) гесьгп Сгце; гесцгп Са1зе; ) ) // Продемонстрировать применение массива с произвсльно задаэаемыми пределами индексирования.
с1азв ВапдеАггаубешо ( зсас1с чогб Маги() ( агу ( ВапдеАггау га = пен ВапдеАггау(-5, 5); ВапдеАггау га2 = пен Вапдепггау(1, 1О); // Использовать объект га в качестве массива. Сопво1е.иг1оеььпе("Длина массива га: " + га.Ьепдсь) Сот(1пс 1 = -5; г <= 5; 1++) га[г] = 1; Сопао1е.мг1ое("Содержимое массива га: "); Сот(1пС г = -5) г <= 5) 1++) Сопво1е.Хг1се(та[1] + " "); Сопво1е.иг1оеЬЬпе ("1п") ) // Использовать объект га2 в качестве массива. сопво1е.хгггеь1пе("длина массива га2: " ь га2.ьепдгь) гог(1пс г = 1; г <= 10~ г++) га2(1] = ).; Сопво1е.Хг1се("Длина массива га2: "); Сот(1пс 1 = 1) г <= 10; 1++) Сопво1е.Хг1ое(га2[1] + " "); Глава 13.
Обработка исключительных ситуаций 425 Сопэо1е.иг1сеъгпе("1п")," ] сапов (НапдеАггауЕхсерсгоп ехс) ( Сопэо1е.игьгеьгпе(ехс); ) А теперь продемонстрировать обработку некоторых ошибок. Сопэо1е.иглгеььпе("Сгенерировать ошибки нарушения гранин."); // Испольэовать неверно заданный конструктор. ггу ( Напделггау гаЗ = лен НапдеАггау(100, -10); // Ошибка! сассл (НапдеАггауЕхсерпгоп ехс) ( Сопэо1е.иг1сеъгпе(ехс); ) О Использовать неверно заданный индекс. ггу ( Капделггау газ = пен ЯапдеАггау(-2, 2); Гог(ьпс 1 = -24 1 <= 2; 1++) гаЗ[1] Сопэо1е.Хггсе("Содержимое массива гаЗ: "); Гог(гпс 1 = -2; 1 <= 104 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 8 9 10 Сгенерировать ошибки нарушения границ. Нижний индекс не меньше верхнего. Содержимое массива гаЗ: -2 -1 0 1 2 Ошибка нарушения границ. Когда возникает ошибка нарушения границ массива класса Еапдейггау, генерируется объект типа ЕапдейггауЕхсерг1оп. В классе Еапдейгта у это может произойти в трех следующих местах: в аксессоре дес индексатора, в аксессоре зес индексатора и в конструкторе класса Еапделггау.
Для перехвата этих исключений подразумевается, что объекты типа Еапдейггау должны быть сконструированы и доступны из блока сгу, что и продемонстрировано в приведенной выше программе. Используя специальное исключение для сообщения об ошибках, класс Еапдейггау теперь дейс)вует как один из встроенных в С() типов данных, и поэтому он может быть полностью интегрирован в механизм обработки ошибок, обнаруживаемых в программе. 426 Часть!.
Язык С() Обратите внимание на то, что в теле конструкторов класса исключения ВапоейттауЕхсертзоп отсутствуют какие-либо операторы, но вместо этого они просто передают свои аргументы классу Ехсертзоп, используя ключевое слово Ьазе. Как пояснялось ранее, в тех случаях, когда производный класс исключений не дополняет функции базового класса, весь процесс создания исключений можно поручить конструкторам класса Ехсертйоп.
Ведь производный класс исключений совсем не обязательно должен чем-то дополнять функции, наследуемые от класса Ехсерсйоп. Прежде чем переходить к дальнейшему чтению, гюпробуйте немного поэкспериментировать с приведенной выше программой. В частности, попробуйте закомментировать переопределение метода тоест1по () и понаблюдайте за результатами. Кроме того, попьпайтесь создать исключение, используя конструктор, вызываемый по умолчанию, и посмотрите, какое сообщение при этом сформируется стандартными средствами С)).