Г. Шилдт - С# 3.0 Полное руководство. 2010 (1160798), страница 113
Текст из файла (страница 113)
Рассмотрим для начала простой пример. В приведенной ниже программе объявляется необобщенный класс йггауОЬ11я, а в нем — статический обобщенный метод Сору1п я его ( ) . Этот метод копирует содержимое одного массива в другой, вводя по ходу дела новый элемент в указанном месте.
Метод сору1пяегс (] можно использовать вместе с массивами любого типа. // Продемонстрировать применение обобщенного метода. ия1пч эуяиевн // Класс обработки нас~ивов. Этот класс не является обобщенным. с1аяя аггауПС11я ( // Копировать массив, вволя по ходу дела новый // элемент. Этот метод является обобщенным. риЫ1с яоа11с Ьоо1 Сору1пяего<т>(т е, Ыпо 1бх, 590 Часть[. Язык С№ Т[] ягс, Т[] Гагдет) ( // Проверить, насколько велик массив. 11(тагдет.Бепдкп < ягс.Ьепдтнь1) гетигп Та1яе) // Скопировать содержимое массива ягс в целевой // массив, попутно введя значение е по индексу 1бх. тот(апт 1=0, 2=0) 1 < ятс.ьепдгпк 1++, 9++) ( 11(). == гбх) ( ' гагдег[3] = е) 9++) ) гагдег[3] = зги[1]) ) гегигп ггие) ) ) с1авя ОепМетнбево ( ягагас чогб маап[) ( Тпт[] пипл ( 1, 2, 3 )) 1пт[] пивя2 = пен 1пс[4]) // Вывести содержимое массива пива.
Сопяо1е.итаке("Содержимое массива пива: "); Тогеасн(1пс х Тп пива] Сопяо1е.итаке(х + " ")) Сопяо1е.ыт1ке11пе() // Обработать массив типа Тпт, Аггаудг11я.Сору1пяетт(99, 2, пива, пивя2); // Вывести содержиыое массива пивв2. Сопяо1е.ыг1те("Содержимое массива пивв2: ")) Тогеасп(1пк х Тп пивя2) Сопяо1е.ыг1се(х + " "); Сопво1е.ыг1ке11пе()) // А теперь обработать массив строк, используя метод сору1пяегт.
яттапд[] яття ("Обобщения", "весьма", "аффективны.")) ятг1пд[] ятгя2 = пеи якгапд(4)) // Вывести содержимое массива яття. Сопяо1е.итаке("Содержимое массива якгяк ")) Тогеасн(ятгапд в ап ятгя) Сопяо1е.ыггее(я + " ")) Сопя о1е. ИгатеВапе () Глава (8. Обобщения 591 // Ввести элемент в массив строк.
Кггаупо11з.Сору1пзегв("в СВ", 1, звгз, зтгз2)/ // Вывести содержимое массива зьгз2. Сопзо1е.иггве("Содержимое массива зтгз2: "); Гвгеась(зогапч з Тп зтгз2) Сопзо1е.иггое(з + " "); Сопзо1е. Нг1веъъпе (); // Этот вызов недопустим, поскольку первый аргумент // относится к типу бонъ1е, а третий и четвертый // аргументы обозначают элементы массивов типа Тпт. // ЛггауОС11з.Сору1пзегь(0.01, 2, пнщз, пнщз2); ) ) Вот к какому результату приводит выполнение этой программы: Содержимое массива ппщз: 1 2 3 Содержимое массива пнщз2: 1 2 99 3 содержимое массива зсгз: Обобщения весьма эффективны. Содержимое массива зтгз2: Обобщения в СВ весьма эффективны.
Внимательно проанализируем метод Сору1пз его ( ) . Прежде всего обратите внимание на объявление этого метода в следующей строке кода: рчь11с зсасъс ьоо1 сору1пзегс<т>(т е, дыло ык, Т() згс, Т(] Сагчео) ( Параметр типа объявляется после имени метода, но перед списком его параметров. Обратите также внимание на то, что метод Сору1пзегг () является статическим, что позволяет вызывать его независимо от любого объекта. Следует, однако, иметь в виду, что обобщенные методы могут быть либо статическими, либо нестатическими. В этом отношении для них не существует никаких ограничений.
Далее обратите внимание на то, что метод Сору1пзегг () вызывается в методе Ма1п () с помощью обычного синтаксиса и без указания аргументов типа. Дело в том, что типы аргументов различаются автоматически, а тип Т соответственно подстраивается. Этот процесс называется выводииосллью типов. Например, в первом вызове данного метода Лггаупт11з.сору1пзегв(99, 2, пнщз, пнщз2) тнп Т становится типом Тпс, поскольку числовое значение 99 и элементы массивов ппщз и ппщз2 относятся к типу Тпг.
А во втором вызове данного метода используются строковые типы, и поэтому тип Т заменяется типом зггап9. А теперь обратите внимание на приведенную ниже закомментированную строку кода. // ЬггауОС11з.сору1пзего(0.01, 2, пнщз, пнщз2)я Если удалить символы комментария в начале этой строки кода и затем попытаться перекомпилировать программу, то будет получено сообщение об ошибке. Дело в том, что первый аргумент в данном вызове метода Сору1пзегг () относится к типу с(оп]э1е, а третий и четвертый аргументы обозначают элементы массивов ппщз и ппщз2 типа 1пс. Но все эти аргументы типа должны заменить один и тот же параметр типа Т, а это приведет 592 Часть (. Язык Сз к несоответствию типов и, как следствие, к ошибке во время компиляции.
Подобная возможность соблюдать типовую безопасность относится к одним из самых главных преимуществ обобщенных методов. Синтаксис объявления метода Сору1пяегс () может быть обобщен. Ниже приведена общая форма объявления обобщенного метода. воэврадаемый тип ими метода<список параметров типа>( список параметров) (// В любом случае список параметров хипа обозначает разделяемый запятой список параметров типа. Обратите внимание на то, что в объявлении обобщенного метода список параметров типа следует посла имени метода.
Вызов обобщенного метода с явно указываемыми аргументами типа В большинстве случаев неявной выводимости типов оказывается достаточно для вызова обобщенного метода, тем не менее, аргументы типа могут быть указаны явным образом. Для этого достаточно указать аргументы типа после имени метода при его вызове.
В качестве примера ниже приведена строка кода, в которой метод Сору1пяегг () вызывается с явно указываемым аргументом типа яггъпд. Аггаупк11я.сору1пяегс<ясгтпд>("1п с()", 1, ясгя, яскя2)т Тип передаваемых аргументов необходимо указывать явно в том случае, если компилятор не сможет вывести тип параметра Т или если требуется отменить выводимость типов. Применение ограничений в обобщенных методах На аргументы обобщенного метода можно наложить ограничения, указав их после списка параметров. В качестве примера ниже приведен вариант метода Сору1пяегг () для обработки данных только ссылочных типов. риъььс якасьс Ьоо1 Сору1пяетк<т>(Т е, ьъпс 1бх, Т[) ятс, Т[) Сатдек) маете Т: с1авя ( Если попробовать применить этот вариант в предыдущем примере программы обработки массивов, то приведенный ниже вызов метода Соругпяегг () не будет скомпилировав, поскольку Тпс является типом значения, а не ссылочным типом.
// Теперь неправильно, поскольку параметр Т должен // быть ссылочного типа! агтауцк11я.сору1пяекк(99, 2, опия, ппия2)т // Теперь недопустимо! Обобщенные делегаты Как и методы, делегаты также могут быть обобщенными. Ниже приведена общая форма объявления обобщенного делегата. де1едасе воэвращаеьпкн тип имя делегата<список параметров хипа>(список аргументов)т Гнева ((). Обобщения 593 Обратите внимание на расположение списка параметров типа.
Он следует непосредственно после имени делегата. Преимущество обобщенных делегатов заключается в том, что их допускается определять в типизированной обобщенной форме, которую можно затем согласовать с любым совместимым методом. В приведенном ниже примере программы демонстрируется применение делегата Вощеор с одним параметром типа Т. Этот делегат возвращает значение типа т и принимает аргумент типа Т. // Простой пример обобщенного делегата. пзгпд 5увсепп // Объявить обобщенный делегат. бе1едасе Т 5ощеор<Т>(Т ч)) с1ава Оепое1едасеоещо ( // Возвратить результат суммирования аргумента.
зсасас 1пс зщп(апс ч) ( Тпс гевп1Г = О; Тот(апс 1=ч) 1>0) 1--) гезо1Г += 1( геспгп гевп1ся // Возвратить строку, содержащую обратное значение аргумента. згас1с зсг1пд Вег1есс(зсг1пд зсг) ( всггпд гезп1Г = ч") Гогеасп(спас сп гп вгг) гевп1Г = сп ь гевп1Г( геспгп гезп1Г) ) вгаг1с човб паап() ( // Сконструировать делегат типа ьпг. 5ощеор<апс> 1псое1 = зпщ; Сопзо1е.нг1геь1пе(1пгве1(3))) // Сконотруировать делегат типа вггьпд.
зощеор<зсгапд> всгпе1 = Кег1есс) Сопзо1е.нгасеьапе(всгве1("Привет" ))) ) ) Эта программа дает следующий результат: 6 тевирП Рассмотрим зту программу более подробно. Прежде всего обратите внимание на следующее объявление делегата Вощеор: бе1едасе Т зощеор<Т>(Т ч); 594 Часть(. Язык С» Как видите, тип т может служить в качестве возвращаемого типа, несмотря на то, что параметр типа Т указывается после имени делегата БощеОр. Далее в классе СепРе1едаСепещо объявляются методы яцщ () и Вег1есг (), как показано ниже. згаг1с ъпг Бцш(ъпе ч) ( зоаеьс згг1пд Не51есг(згг1пд згг) ( Метод Яцщ () возвращает результат суммирования целого значения, передаваемого в качестве аргумента, а метод Бег1есС () — символьную строку, которая получается обращенной по отношению к строке, передаваемой в качестве аргумента.
В методе ма1п () получается экземпляр Тпспе1 делегата, которо.. присваивается ссылка на метод Бцщ (): Бошеор<ъпе> 1пгпе1 = Бош," Метод Яцщ () принимает аргумент типа Тпс и возвращает значение типа Тпс, поэтому он совместим с целочисленным экземпляром делегата ЯощеОр. Аналогичным образом получается экземпляр зсгпе1 делегата, которому присваивается ссылка на метод НеТ1есг (): яошеор<зогъпд> зогпе1 = Не»1есо/ Метод Нег1есС () принимает аргумент типа згг»пд и возвращает результат типа згг1пд, поэтому он совместим со строковым экземпляром делегата Яощебр. В силу присущей обобщениям типовой безопасности обобщенным делегатам нельзя присваивать несовместимые методы. Так, следующая строка кода оказалась быть ошибочной в рассматриваемой здесь программе: Боюеор<ъпг> 1пгве1 = Вег1есг; // Ошибка! Поскольку метод БеТ1есс () принимает аргумент типа зсгъпд и возвращает результат типа згг1пд, он несовместим с целочисленным экземпляром делегата ЯощеОр.
Как пояснялось в главе 15, делегаты чаще всего применяются при обработке событий. И хотя сами события не могут быть обобщенными, таковыми могут быть поддерживающие их делегаты. Приведенная ниже программа является вариантом примера из главы 15, демонстрирующего .)ь)ЕТ-совместимое событие. Этот вариант был переделан с целью показать применение обобщенного делегата.