Г. Шилдт - С# 3.0 Полное руководство. 2010 (1160798), страница 110
Текст из файла (страница 110)
Для управления списками телефонных номеров создадим еще один класс под названием РЬопеифзю Его следует сделать обобщенным, поскольку ои должен служить для управления любым списком телефонных номеров. В функции такого управления должен, в частности, входить поиск телефонных номеров по заданным именам, и наоборот, поэтому иа данный класс необходимо наложить ограничение по типу, требующее, чтобы объекты, сохраняемые в списке, были экземплярами класса, производного от класса РЬопеипюЬег. // Класс Рпопе11зг способен управлять любым видом // списка телефонных номеров, при условии, что он // является производным от класса РпопеипюЬег.
с1азз Рьопег Тзг<т> ньеге т : Рьопенпюьег ( т[) рпьазл; Тпл епб/ рпЫТс Рпопегазс () ( рпдазс = пен Т[10)г епб = Оя ) // Добавить элемент з список. рпЬ11с Ьоо1 йбб(Т пенкплгу) ( ТТ(епб = 10) гелигп Еа1зе) рплазс[епб) = пенЕплгу) елось) гелпгп Ггпе; // Найти и возвратить сведения о телефоне по заданному имени. риЫ1с Т Е1пбзунаюе(зсг1по пате) гог(1пг 1 0; 1<епбя 1++) ( // Имя может использоваться, потому что его // свойство Иаюе относится к членам класса // РпопеипюЬег, который является базовым по // накладываемому ограничению.
572 Часть ). Язык С» 1Е(рпььзг[1) .Иаие == паве) геспгп рптгзс[1)г ) // Имя отсутствует в списке. Спгом пеи ИосгоппбЕхсергфоп(); ) // Найти и возвратить сведения о телефоне по // заданному номеру. рпЬ1»с Т Г1пбзуыоюЬег(згг1пс ппюЬег) ( тог(ьпг 1=0; 1<елок 1++) ( О Номер телефона также может использоваться, // поскольку его свойство Иокпег относится к // членам класса РЬопеыоюЬег, который является // базовым по накладываемому ограничению.
11(рЬЕ»вг[1).ыоюбег == поюпег) гесогп РЬЕ»зс[1); ) // Номер телефона отсутствует в списке. Спгон пеи ИогГоипбЕхсерс1оп()т ) Ограничение на базовый класс разрешает коду в классе рьопее»ас доступ к свойствам Иаюе и Ипюбег для управления любым видом списка телефонных номеров. Оно гарантирует также, что для построения объекта класса рьопее»зс будут использоваться только доступные типы. Обратите внимание на то, что в классе рпопеЬ»зе генерируется исключение иосроипбехсерс1оп, если имя или номер телефона ие найдены. Это специальное исключение, объявляемое ниже. с1азз ИосгоопбЕхсерсфоп т Ехсергфоп [ /* Реализовать все конструкторы класса Ехсергфоп.
Зти конструкторы выполняют вызов конструктора базового класса. Класс ИосгоппбЕхсерсфоп ничем не дополняет класс Ехсергъоп и поэтому не требует никаких дополнительных действий. */ рпЬ11с ИосгоопбБхсерг1оп(): Ьазе() ( ) роба»с ИогГоопбЕхсерс1оп(зсгьпд зсг) т Ьазе(вгг) ( ) рчЬ1»с ИоСГоопбЕхсергфоп( всг1по згг, Ехсерс1оп 1ппег): Ьазе(зсг, 1ппег) ( ) ргосесгеб ИоСГоипбЕхсерстоп( Яузсею.пспг»юе.зегьа1»каг1оп.5егьа11закьоптпто зф, 5узсею.хппс1юе.5егьа11хастоп.зсгеаитпусопсехг зс) Ьазе(з1, зс) ( ) ) В данном примере используется только конструктор, вызываемый по умолчанию, но ради наглядности этого примера в классе исключения ИосроипбЕхсерефоп реализуются все конструкторы, определенные в классе ехсерс»оп.
Обратите внимание иа то, что Глава! 8. Обобщения 573 эти конструкторы вызывают эквивалентный конструктор базового класса, определенный в классе Бхсерг1оп. А поскольку класс исключения Носроцпбкхсерг1оп ничем не дополняет базовый класс Бхсерсфоп, то для любых дополнительных действий нет никаких оснований. В приведенной ниже программе все рассмотренные выше фрагменты кода объединяются вместе, а затем демонстрируется применение класса РЬопеъфзг.
Кроме того, в ней создастся класс Бща11рг1епоб Этот класс не наследует от класса РпопеицюЬег, а следовательно, он не может использоваться для создания объектов класса Рьопеъфзс. // Более практический пример, демонстрирующий применение // ограничения на базовый класс. цзг по 5увсехп // Специальное исключение, генерируемое в том случае, // если имя или номер телефона не найдены. с1авз Носроцпбкхсерс1оп я Бхсерсфоп ( /* Реализовать все конструкторы класса Ехсерсгоп. Эти конструкторы выполняют вызов конструктора базового класса. Класс МосгоцпбЕхсерсаоп ничем не дополняет класс Ехсерсфоп и поэтому не требует никаких дополнительных действий.
*/ рцбаас НосгоцпбЕхсерсфоп(): паве() ( ) рцбагс НосгоопбЕхсерсфоп (всг1пд зсг) : Ьазе(всг) ( ) рцбаас НосгоцпбЕхсерсфоп( всггид всг,Ехсерггоп 1ппег) : Ьазе(зсг, хппег) ( ) ргосессеб НоггоцпбБхсерсфоп( зузсещ.ацпгфще.зегфа1(хасфоп.5ег1а11гагаоп1пто в(., 5узсещ.ацпсияе.зегга11гасвоп.5сгеащзидСопгехг вс) Ьаве(в1, зс) ( ) // Базовый класс, в котором хранятся имя абонента и номер его телефона. с1авв РпопеицюЬег ( рцЬ11с РпопеицюЬег(згггпд п, зсггпд пцщ) ( наще = и; НшпЬег = пцщ; ) рцЬ11с всгфпд НшяЬег ( дес; вес; рцнафс зсг1пд Наюе ( дес; зес; ) ) // Класс для телефонных номеров друзей. с1азз Ргаепб: РпопеицщЬег ( рцбггс Ргфепб(вггапд и, всг1пд пшя, Ьоо1 нн) Ьазе (и, пшл) 1зногниоюЬег ннг ) 574 Часть (, язык С» риьаас ьоо1 1виогкнивьег ( феты ргачаге вест ) // Класс для телефонных номеров поставщиков.
с1азз Эирр11ег т РпопеЮивЬег [ риЬ11с Эирр11ег(зсг1по и, зсг1пО пив) Ьазе(п, пив) ( ) // Этот класс не наследует от класса РпопенивЬег. с1азз Ева11Ргаепб ( // ... ) //,Класс РпопеЕ1зг способен управлять любым видом // списка телефонных номеров, при условии, что он // является производным от класса РпопенивЬег. с1азз Рьопееазг<т> ньеге т т Рьопемивпег ( т(! Рльфзст спг епс(т риЬ11с Рнопе)1зг() ( РЬЬТзс = пен Т[10]т епб = О) // )[сбавить элемент в список„ риЬ11с Ьоо1 Асб(Т пенепггу) ( ТТ(епб == 10) гесигп Та1зе) рп[фзс[епб! пенЕпсгу) епбььт гесигп сгиет ) // Найти и возвратить сведения о телефоне по // заданному имени.
риЬ11с Т Р1псйунаве(зсг1пц паве) ( Рог(апс 1 0) 1<ело) 1++) ( // Имя может использоваться, потому что его // свойство Юаве относится к членам класса // РпопенивЬег, который является базовым по // накладываемому ограничению. ТТ(рп11зс[1!.Наве == паве) гесигп рптазг(1!) // Имя отсутствует в списке.
Глава (8. Обобщения 575 Гитон пен НоГГоопбЕхсерсфоп() ) // Найти и возвратить сведения о телефоне по // заданному номеру. рнбаас Т ГапбВуншвЬег(ясг1пд пшпЬег) ( Еог[апг 1=0) 1<ело) 1ь.ь) ( // Номер телефона также может использоваться, // поскольку его свойство НнюЬег относится к // членам класса РЬопенчщЬег, который является // базовым по накладываемому ограничению. гй(рЬЕ1вв(1].ноюЬег == поюЬег) геспгп рпйфяс[1]л // Номер телефона отсутствует в списке. Гпгон пен ИосуоппбЕхсерсаоп () ) ) // Продемонстрировать наложение ограничений на базовый класс.
с1авв ПяеВаяеС1аявСопясгаапс ( ясасас чоаб Ма1п() ( // Следующий код вполне допустим, поскольку класс ° // Ггаепб наследует от класса РпопеноюЬег. Рпопе11вс<Гг1епб> р11яс = пен Рпопе11яс<Гг1епб>()л р11вс.йбс((пен Гг).епб("Том", "555-1234", Ггие))) р11яс.доем(пен Гг1епб("Гари", "555-б75б", Ггие) ) л р11яв.й<(с((пен Гг1епб("Матт", "555-9254", Та1зе) ) ) ггу ( // Найти номер телефона по заданному имени друга.
Ггфепб Тгпб р11яГ.Г1пбйу)лазе("Гари" ); Сопяо1е.нг1Ге(ггпб.наюе + ": " + Ггпб.ншяЬег)) 11 (Егпб. 1яноглнпюпег) Сопяо1е.нг1се11пе(" (рабочий)" )) е1яе Сопво1е.ИгасеЕгпе()' ) пасси(ноГГоппбЕхсерсаоп) ( Сопзо1е.Игасе11пе("Не найдено"); ) Сопяо1е.нгаве11пе() // Следующий код также допустим, поскольку класс // Ечрр11ег наследует от класса РпопеншвЬег. РЬопе51яс<Яорр11ег> р11яс2 = пен РЬопе11яг<яорр11ег> (); р11яс2.лбб(пен Еорр11ег( 676 часть ).
язык сз "Фирма О1ооа1 Нагбнаге", "555-8834"))т р11вс2.Абб(пеи зпрр11ег( "Агентство Сошросег Иагепоове", "555-9256"))т р11вс2.Або(пеи зорр11ег( "Компания Несиогхсгсу", "555-2564"))т ггу ( // Найти наименование поставщика по заданному номеру телефона. зорр11ег вр р11вг2.Р1пбвуиошЬег("555-2564")т Сопво1е.нггсе61пе(вр.наше + ": " + яр.нншЬег)т ) сассп(носгонпбЕхсерггоп) ( Сопво1е.Иг1геьгпе("Не найдено"); // Следующее объявление недопустимо, поскольку // класс Еша11гг1епб НЕ наследует класс РпопенШПЬег. // Рпопе11вс<Еша11гггепб> р11всз = // пен Рьопеь1вг<еша11гггепб>()т // Ошибка! Ниже приведен результат выполнения этой программы.
Гари: 55-6756 (рабочий) Компания НепногКСРГу: 555-2564 Поэкспериментируйте с этой программой. В частности, попробуйте сеставить разные виды списков телефонных номеров или воспользоваться свойством 1вногкношЬег в классе Рйопенфвг. Вы сразу же обнаружите, что компилятор не позволит вам этого сделать, так как свойство 1вног)<ншпЬег определено в классе Рг1епф а не в классе РнопеншпЬег, а следовательно, оно неизвестно в классе Рпопенфвс. Применение ограничения на интерфейс Ограничение на интерфейс позволяет указывать интерфейс, который должен быть реализован аргументом типа.
Это ограничение служит тем же основным целям, что и ограничение на базовый класс. Во-первых, оно позволяет использовать члены интерфейса в обобщенном классе. И во-вторых, оно гарантирует использование только тех аргументов типа, которые реализуют указанный интерфейс. Это означает, что для любого ограничения, накладываемого на интерфейс, аргумент типа должен обозначать сам интерфейс или же тип, реализующий этот интерфейс. Ниже приведена общая форма наложения ограничения на интерфейс, в которой используется оператор шлете. ньеге Т: имя интерФейса где 7 — это имя параметра типа, а иия интерфейса — конкретное имя ограничиваемого интерфейса.
В этой форме ограничения может быть указан список интерфейсов через запятую. Если ограничение накладывается одновременно на базовый класс и интерфейс, то первым в списке должен быть указан базовый класс. Ниже приведена программа, демонстрирующая наложение ограничения на интерфейс и представляющая собой переработанный вариант предыдущего примера программы, управляющей списками телефонных номеров.
В этом варианте класс РЬопенпшЬег преобразован в интерфейс 1РЬопеиошЬег, который реализуется в классах Рг1епб и Вирр11ег. Глава! 8. Обобщения 577 // Применить ограничение на интерфейс. ия1пф Эуягепи // Специальное исключение, генерируемое в том случае, // если имя или номер телефона не найдены.