Г. Шилдт - С# 3.0 Полное руководство. 2010 (1160798), страница 111
Текст из файла (страница 111)
с1азя МоСГоипбЕхсергуоп: Ехсергаоп ( /* Реализовать все конструкторы класса Ехсергаоп. Эти конструкторы выполняют вызов конструктора базового класса. Класс МогуоипбЕхсерг1оп ничем не дополняет класс Ехсергаоп и поэтому не требует никаких дополнительных действий. */ риыас мосГоипбехсерсаоп() : Ьаяе() ( риь11с мосуоипбехсерс1оп(встав ясг): ьаяе(ясг) ( риЫас МоСГоипбЕхсерСаоп( зСгапо зпг,Ехсерпаоп 1ппег) и Ьаяе(згг, аппег) ( ) ргогесгеб МоСГоипбЕхсерС1оп( 5узгею.нипС1юе.5егаа11гагаоп.вегаа11зас1оп1пео з1, 5уясею.хипсаюе.5ег1а11гасуоп.всгеаюапосопсехс зс) Ьазе(з)., зс) ( ) // Интерфейс, подлерживаююий имя и номер телефона.
риЫас апгегуасе 1РЬопениюЬег ( ягг1пд Миюпег ( алеся яес) ) ягг1пд Маме ( ПеЫ яес) ) // Класс для телефонных номеров друзей. // В нем реализуется интерфейс 1РЬопениюЬег. с1азя Ггаепб: 1РЬопениюЬег ( риЫ1с Ггаепб(яггспд и, ягг1пс пию, Ьоо1 нс) ( Маме = и) МиюЬег = пию; ХяиогнниюЬег = нн) ) риыус ьоо1 1яиогхмиюьег ( Песп ргачасе зес; ) // Реализовать интерфейс 1РЬопениююег. риь11с вступи миюьег [ алеся зес; ) 578 Часть !. Языг С(( рпЬ11с зсгфпд Мате ( цес) зес; // ) // Класс для телефонных номеров поставщиков. с1азз 5орр11ег: 1РЬопенощЬег ( рпЬ11с 5орр11ег(зсг1пд и, зпг1пд пощ) [ Маме = и) МоюЬег = ппщ; ) // Реализовать интерфейс 1РЬопенощЬег.
рпбуфс зсг1пц Моюпег ( дев; зез; ] роЬ11с зсг1пд Маме ( алесь зес; ) // ) // В этом классе интерфейс 1РЬопенощЬег не реализуется. с1азз Еща11Рг1епб ( // ... ) // Класс РпопеЬТзс способен управлять любым видом // списка телефонных номеров, при условии, что он // реализует интерфейс РпопеМощЬег. с1азз РЬопеЬТзп<Т> нпеге Т: ХРЬопенощЬег ( Т[] РЬЕТзп; Тпг епФ роЬ11с РпопеЬТзс() ( рпйфзс пен Т[10]: епб = 0; ) роЬ11с Ьоо1 Абб(Т пенЕпсгу) гб(епб == 10) гесогп Та1зеу РЬЕ1зп[епб] = пенЕпсгу; епб++; гегпгп ггое; ) // Найти и возвратить сведения о телефоне по заданному имени. роЬ11с Т РфпНВунаще(зсг1пц паве) ( Рог(фпг 1=0; 1<епб) 1++) ( ' // Имя может использоваться, потому что его // свойство Мате относится к членам // интерфейса 1РЬопенщзпег, на который // накладывается ограничение.
ТТ(РЬЕ1зп[1].Мазе == паве) Глава (8. Обобщения 579 гегпгп РППавг(1)) ) // Имя отсутствует в списке. ппгон пен иопеоппсБхсерг1оп()п ) // Найти и возвратить сведения о телефоне по заданному номеру. рпЬ11с Т Е1пп(ВунпвЬег(впгапо ппвЬег) ( гог(1пп 1=0) 1<епбп 1+П) ( // Номер телефона также может использоваться, // поскольку его свойство ИпвЬег относится к // членам интерфейса 1РЬопенпвЬег, на который // накладывается ограничение.
/ 16(рабаап[1].нпвЬег == ппвпег) геппгп рпбазг(1)п ) // Номер телефона отсутствует в списке. Питон пен НоПГоппбахсерп1оп()) // Продемонстрировать наложение ограничения на интерфейс. с1азп Пве1ппеггасесопвпга1пг ( вгагас чогй Мауп() ( // Следующий код вполне допустим, поскольку в // классе Егаепб реализуется интерфейс 1РЬопенпвЬег. Рпопе11вп<Ег1епб> р11вг = пен РЬопе51зг<Ег1епб>()п р11аг .А<И (пен Ег1епб (6 Ром", "555-1234", Пгпе) ) 7 р11зг.йбб(пен Ег1епб("Гари", "555-6756", Ггпе)); р11вг.йбб(пен Ег1епб("Матт", "555-9254", Га1ве))) ггу ( // Найти номер телефона по заданному имени друга. Ег1епб Ггпп( = р11аг.е1пп)Вунаве("Гари")и Сопво1е.нг1пе(ггпб.наве + ": " и Егпб.нпвЬег)п 16(лгпб.1вногхнпвпег) Сопво1е.иг1пей1пе(" (рабочий)" )) е1зе Сопзо1е.иг1пе11пе()7 ) сагсп(ногуоппбахсерпаоп) ( Сопво1е.нгагебапе("Не найдено")7 ) Сопяо1е .Игапебапе () ) // Следующий код также допустим, поскольку в 880 Часть ), ))аык ь№ // классе Япрр11ег также реализуется // интерфейс 1РЬопеып~пЬег.
РЬопеъъвг<зорр11ег> р11вс2 пен РЬопеьтвс<зирр11ег>(); р11вг2.Абб(пен Янрр11ег( "Фирма Я1ОЬа1 Нагдмаге", "555-8834")); р11вг2.Абб(пен Япрр11ег( "Агентство Сошрпсег Иагеьоизе", "555-9256"))) р11вс2.Абб(пен Яирр11ег( "Компания Несногкс1су", "555-2564")); ггу ( // Найти наименование поставщика по заданному номеру телефона. Янрр11ег вр р11вс2.Г1пбвуыошЬег("555-2564")) Сопво1е.ыгъгеьтпе(вр.наше 4 ": " т,зр.ищпЬег)) ) сассЬ(иосгоппбвксергъоп) Сопво1е.ыгтгеъ№пе("Не найдено")4 ) // Следующее объявление недопустимо, поскольку // в классе Еша11ггтепб НЕ реализуется // интерфейс ХРЬопеиншъег. // Рьопеь№вь<еша11тгъепб> р11вг3 = О пен Рьопеьтвс<еша11тгтепб>()4 // Ошибка! ) ) В этой версии программы ограничение иа интерфейс, указываемое в классе РЬопеъъзг, требует, чтобы аргумент типа реализовал интерфейс 1РЬопеъ№зс.
А поскольку этот интерфейс реализуется в обоих классах, Рг1еп<) и Япрр1№ег, то оии относятся к допустимым типам, привязываемым к типу Т. В то же время интерфейс ие реализуется в классе Еща11ргъепб, и поэтому этот класс ие может быть привязан к типу т. Для того чтобы убедиться в этом, удалите символы комментария в двух последних строках кода в методе ма1п () . Вы сразу же обнаружите, что программа ие компилируется.
Применение ограничения шеф№ () на конструктор Ограничение пен () иа конструктор позволяет получать экземпляр объекта обобщеиного типа. Как правило, создать экземпляр параметра обобщенного типа ие удастся. Но это положение изменяет ограничение пен (), поскольку оио требует, чтобы аргумент типа предоставил конструктор без параметров. Им может быть конструктор, вызываемый по умолчанию и предоставляемый автоматически, если явно определяемый конструктор отсутствует или же конструктор без параметров явно объявлен пользователем. Накладывая ограничение пеи (), можно вызывать конструктор без параметров для создания объекта.
Ниже приведен простой пример, демонстрирующий наложение ограничения пен () . // Продемонстрировать наложение ограничения пен() // на конструктор. ов1пч Яувсево с1азз МуС1авв ( Глава 18. Обобя(янин 581 рпвггс МуС1авя () ( // ... ) с1авя тевс<т> нпеге т: пен() ( Т оЬ1; рпЬ11с Тевя() ( // Этот код работоспособен благодаря наложению ограничения пен().
оЬ) пен Т()) // создать объект типа Т ) с1авв СопяСопвягагпяоеюо ( явая1с чоьб Магп() ( теяс<мус1аяя> х пен тевс<мус1авя>() ) Прежде всего обратите внимание на объявление класса Теяг: с1авв Теяя<т> инесе Т: пен() ( В силу накладываемого ограничения пен() любой аргумент типа должен предоставлять конструктор без параметров. Далее проанализируем приведенный ниже конструктор класса теяь. ровггс Теяя() // Этот код работоспособен благодаря наложению // ограничения пен(). оЬ1 = пен Т(); // создать объект типа Т ) В этом фрагменте кода создается объект типа Т, и ссылка на него присваивается переменной экземпляра оЬ1.
Такой код допустим только потому, что ограничение лен () требует наличия конструктора. Для того чтобы убедиться в этом, попробуйте сначала удалить ограничение пен (), а затем попытайтесь перекомпилировать программу. В итоге вы получите сообщение об ошибке во время компиляции. В методе ма1п () получается экземпляр объекта типа те яь, как показано ниже. Теяя<иус1авя> х пен Тевя<иус1авя>() Обратите внимание на то, что аргументом типа в данном случае является класс Мус1аяя и что в этом классе определяется конструктор без параметров.
Следовательно, этот класс допускается использовать в качестве аргумента типа для класса те в с. Следует особо подчеркнуть, что в классе Мус1авв совсем не обязательно определять конструктор без параметров явным образом. Его используемый по умолчанию конструктор вполне 582 Часть!. Язык Сз удовлетворяет накладываемому ограничению. Но если классу потребуются другие конструкторы, помимо конструктора без параметров, то придется объявить явным образом и вариант без параметров. Что касается применения ограничения пеы (), то следует обратить внимание на три других важных момента. Во-первых, его можно использовать вместе с другими ограничениями, но последним по порядку. Во-вторых, ограничение пеы() позволяет конструировать объект, используя только конструктор без параметров, — даже если доступны другие конструкторы. Иными словами, передавать аргументы конструктору параметра типа не разрешается.
И в-третьих, ограничение пеи () нельзя использовать в сочетании с ограничением типа значения, рассматриваемым далее. Ограничения ссылочного типа и типа значения Два других ограничения позволяют указать на то, что аргумент, обозначающий тип, должен быть либо ссылочного типа, либо типа значения. Эти ограничения оказываются полезными в тех случаях, когда для обобщенного кода важно провести различие между ссылочным типом и типом значения. Ниже приведена общая форма ограничения ссылочного типа. нпеге Т: с1аяя В этой форме с оператором ыпеге ключевое слово с1аяя указывает на то, что аргумент т должен быть ссылочного типа.
Следовательно, всякая попытка использовать тип значения, например Тпг или Ьоо1, вместо Т приведет к ошибке во время компиляции. Ниже приведена общая форма ограничения типа значения. ипеге Т: яггпсс В этой форме ключевое слово ясгпсс указывает на то, что аргумент т должен быть типа значения. (Напомним, что структуры относятся к типам значений.) Следовательно, всякая попытка использовать ссылочный тип, например ягг1пд, вместо Т приведет к ошибке во время компиляции. Но если имеются дополнительные ограничения, то в любом случае с1аяя или яггисг должно быть первым по порядку накладываемым ограничением. Ниже приведен пример, демонстрирующий наложение ограничения ссылочного типа.
// Продемонстрировать наложение ограничения ссылочного типа. оязпл Зуягеюк с1авя МуС1авя ( //. ° ° // Наложить ограничение ссылочного типа. с1аяя теяг<т> ньеге т: с1аяя ( т оьб; рнЬ11с Теяг() ( // Следуюиий оператор допустим только потому, что // аргумент Т гарантированно относится к ссылочному // типу, что позволяет присваивать пустое значение. оЬЗ пи11; Глава (8. Обобщения 683 с1аяя С1аяяСопясгагпспешо ( ясасус нота паап() ( // Следующий код вполне допУстим, поскольку МуС1аяя является классом.
теяг<мус1аяя> х = пеи теяг<мус1аяя>()) // Следующая строка кода содержит ошибку, поскольку // Тпг относится к типу значения. // Теяс<1пс> у = пен Теяс<ьпс> (); ) Обратите внимание на следующее объявление класса теясх с1аяя Теяс<Т> нпеге Т: с1аяя [ Ограничение с1азз требует, чтобы любой аргумент Т был ссылочного типа. В данном примере кода это необходимо для правильного выполнения операции присваивания в конструкторе класса тезт.
рпю11с Теяс() ( // Следующий оператор допустим только потому, что // аргумент Т гарантированно относится к ссмлочному // типу, что позволяет присваивать пустое значение. оь) = по11; В этом фрагменте кода переменной о)>1 типа Т присваивается пустое значение. Такое присваивание допустимо только для ссылочных типов. Как правило, пустое значение нельзя присвоить переменной типа значения. (Исключением из этого правила является обнуляемый тип, который представляет собой специальный тип структуры, инкапсулирующий тип значения и допускающий пустое значение (пп11). Подробнее об этом — в главе 20.) Следовательно, в отсутствие ограничения такое присваивание было бы недопустимым и код не подлежал бы компиляции.