Г. Шилдт - С# 3.0 Полное руководство. 2010 (1160798), страница 88
Текст из файла (страница 88)
Следовательно, когда создается делегат, то в итоге получается объект, содержащий ссылку иа метод. Более того, метод можно вызывать по этой ссылке. Иными словами, делегат позволяет вызывать метод, иа который ои ссылается. Ниже будет показано, насколько действенным оказывается такой принцип. Следует особо подчеркнуть, что один и тот же делегат может быть использован для вызова разных методов во время выполиеиия программы, для чего достаточно изменить метод, иа который ссылается делегат.
Таким образом, метод, вызываемый делегатом, определяется во время выполнения, а ие в процессе компиляции. В этом, собственно, и заключается главное преимущество делегата. На заметку! Если у вас имеется опыт программирования на С/С++, то вам полезно будет знать, что делегат в С№ подобен функции в С/С-ь+. 458 Часть(, язык Сз Тип делегата объявляется с помощью ключевого слова бе1едасе. Ниже приведена общая форма объявления делегата.
бе1ечаге воэвращаемквй тип имя(список параметров); где возвращаемый тип обозначает тип значения, возвращаемого методами, которые будут вызываться делегатом; имя — конкретное имя делегата; список параметров— параметры, необходимые для методов, вызываемых делегатом. Как только будет создан экземпляр делегата, он может вызывать и ссылаться на те методы, возвращаемый тип и параметры которых соответствуют указанным в объявлении делегата.
Самое главное, что делегат может служить для вызова любого метода с соответствующей сигнатурой и возвращаемым типом. Более того, вызываемый метод может быть методом экземпляра, связанным с отдельным объектом, или же статическим методом, связанным с конкретным классом. Значение имеет лишь одно: возвращаемый тип и сигнатура метода должны быть согласованы с теми, которые указаны в объявлении делегата. Для того чтобы показать делегат в действии, рассмотрим для начала простой пример его применения: // Простоя пример применения делегата.
пяспд Зуягещ; // Объявить тип делегата. бе1едаге вСгапд ЗСгиоб(якг1пд ягг) с1аяя Ое1ечаСетеяС ( // Заменить пробелы дефисами. ягаС1с ягг1пп Вер1асеэрасев(ягг1пд в) ( Сопяо1е.нг1Сеътпе("Замена пробелов дефисами.") гегигп я.вер1асе(' ', '-'); ) // Удалить пробелы. ягагьс ягг1пд Вещотеэрасея(яггьпп в) ( ясг1пч сещр = ""; ьпс ].; Сопво1е.нг1Сеъьпе("Удаление пробелов."); Еог(ъ=ск 1 < я.ьепдгнк 1+Ь) 11(в[1] != ' ') Сещр += в[1]; геспгп сещр; ) // Обратить строку. яСаоас вгг1пч Петегяе(яггъпд в) ( вгг1пд Сещр = ""; 1пг 1, Сопяо1е.игьгеъьпе("Обращение строки."); Тот(]=0, 1 я.ъепцгп-1г 1 >= 0; 1--, 0++) Сещр += я[1]; геспгп сещр: ) Глава 15. Делегаты, события и лямбда-выражения 459 ясасас но1б Мвъп() ( // Сконструировать делегат. яггмпб яггор =.пем яггмоб(вер1всеярасея)т вгг1пд вггт // Вызвать методы с помощью делегата.
всг = ясгбр("Это простой тест."); сопяо1е.нгьгеьапе("Результирующая строка: " + вгг)т Сопяо1е.иг1сеъ1пе()т астор = пен Бсгмоб(аещонезрвсея)т всг = ясгор(ьзто простой тест."); сопяо1е .нгагет Рве ("Результирующая строка: " + ягг) Сопяо1е .Нг1сет ьпе () т всгбр = пен Ясгмоб(кенегяе)~ ясг = ясгор("Это простой тест."); Сопяо1е.ыггсеь1пе("Результирующая строка: " + всг) ) Вот к какому результату приводит выполнение этого кода: Замена пробелов дефисами. Результирующая строка: Это-простой-тест.
Удаление пробелов. Результирующая строка: Зтопростойтест. Обращение строки. Результирующая строка: .тсет йотсорп птЭ Рассмотрим данный пример более подробно. В его коде сначала объявляется делегат Бтгмос) типа ясг1пд, как показано ниже. бе1едвсе ясг1пд Бсгмсб(всг1пд всг) Как вщ(ите, делегат я сгмоб принимает один параметр типа я С г1пд и возвращает одно значение того же типа. Далее в классе Ое1едасетеяс объявляются три статических метода с одним параметром типа ятг1пд и возвращаемым значением того же типа.
Следовательно, ОНИ СО- ответствуют делегату Бггмосд Эти методы видоизменяют строку в той или иной форме. Обратите внимание на то, что в методе нер1асеБрасея () для замены пробелов дефисами используется один из методов типа я с г1пд — Нер1асе () . В методе ма1п () создается переменная экземпляра яггбр ссылочного типа Бггмоб и затем ей присваивается ссылка на метод Нер1асе Брасе я ( ) . Обратите особое внимание на следующую строку кода: Ясгмоб всгор = пем Ясгмоб(аер1асезрвсея) В этой строке метод Нер1асеБрасея() передается в качестве параметра.
При этом указывается только его нмя, но не параметры. Данный пример можно Обобщ)пъ: при получении экземпляра делегата достаточно указать только нмя метода, на который должен ссылаться делегат. Ясно, что сигнатура метода должна совпадать с той, что указана в объявлении делегата. В противном случае во время компиляции возникнет ошибка 460 Часть!. Язык С№ Далее метод нер1асеярасез () вызывается с помошью экземпляра делегата зсгОр, как показано ниже. вгг = вггор("Это простой тест."); Экземпляр делегата зсгОр ссылается на метод Нер1ааезрааез (), и поэтому вызывается именно этот метод. Затем экземпляру делегата этгОр присваивается ссылка на метод Нещочезрааез (), и с его помо)цью вновь вызывается метод — на этот раз метод нещочеЯрасез () .
И наконец, экземпляру делегата зсгОр присваивается ссылка на метод кечегзе () . А в итоге вызывается именно этот метод. Главный вывод из данного примера заключается в следующем: в тот момент, когда происходит обращение к экземпляру делегата астор, вызывается метод, на который он ссылается. Следовательно, вызов метода разрешается во время выполнения, а не в процессе компиляции.
Групповое преобразование делегируемых методов В версии 2.0 в С№ внедрено новое средство, существенно упрощающее синтаксис присваивания метода делегату. Это так называемое групповое преобразование методов, позволяюшее присвоить имя метода делегату, не прибегая к оператору пеи или явному вызову конструктора делегата. Ниже приведен метод Ма1п () из предыдуШего примера, переделанный с целью продемонстрировать групповое преобразование методов. втаага чоьй Мвтп() ( // Сконструировать делегат, иапользуя групповое // преобразование методов.
Ятгноб затор = Вер1ааезрасев~ // иапользоввть групповое преобразование методов заг1пч всг; // Вызвать методы с помощью делегата. ваг = затор("Это проатой тест."); Сопво1е.Иггаеввпе("Результирующая строка: " + ваг)~ Сопво1е.Иг1ееьтпе(); зпгор = Кеюочеэрасев; // использовать групповое преобразование методов зпг = валор("Это простой тест."); сопзо1е.иг1сеьтпе("Результирующая строка: " + зсг); Сопво1е.нг1се11пе М > затор = Нечегве; // использовать групповое преобразование методов вгг = валор("Это простой тест."); Сопво1е.нг1ее11пе("Результирующая строка: " + впг); Сопво1е .Иг1аег Япе (): ) Обратите особое внимание на то, как создается экземпляр делегата з егор и как ему присваивается метод Нер1асе5расез в следующей строке кода: затор = Нещочеэрасев~ // использовать групповое преобразование методов Глвев 15.
Делегаты, события и лямбда-еырвжения 461 В этой строке кода имя метода присваивается непосредственно экземпляру делегата астор, а все заботы по автоматическому преобразованию метода в тип делегата возлагаются иа средства С№. Этот синтаксис может быть распространен иа любую ситуацию, в которой метод присваивается или преобразуется в тип делегата. Синтаксис группового преобразования методов существенно упрощен по сравнению с прежним подходом к делегированию, поэтому в остальной части книги используется именно ои.
Применение методов экземпляра в качестве делегатов В предыдущем примере использовались статические методы, ио делегат может ссылаться и иа методы экземпляра, хотя для этого требуется ссылка иа объект. Так, ниже приведен переделанный вариант предыдущего примера, в котором операции со строками иикапсулируются в классе Яег1пдорв. Следует заметить, что в данном случае может быть также использован синтаксис группового преобразования методов. // делегаты могут ссылаться и на методы экземпляра.' ов1пд Яувтелы // Объявить тип делегата.
бе1еоаге вог1пч Ясгиоб(вгг1пд вгг] с1авв Яог1поорв ( // Заменить пробелы дефисами. риЫ1с втг1по Вер1асеэрасев(ввггпд в) ( Сопво1е.ыг11еЬгпе("Замена пробелов дефисами.")/ гегдгп в.аер1асе(' ', '-')т // Удалить пробелы. рпЫгс ввг1пд Вемонезрасев(вог1по в) ( втг1по Семр = ""; гпг 1; Сопво1е.ыг1Сеьфпе("Удаление пробелов.") лог(г=О) г < в.ЬепОСП/ 1++) ЬГ(в[г] 1= ' ') оеар += в[1]г геппгп Семрт // Обратить строку.
риЫгс вдг1пд веселее(вог1пч в) ( вгг1пд геир = ""г ]пт 1, Сопво1е.иггаеЬгпе("Обрашение строки.")т лог(5=0, 1=в.ьепчгп-1г 1 >= Ог г--, бтт) оеар ь= в[].]г гегпгп геирт ) 462 Часть(. язык Сз с1авв Ое1едаветевв ( вкас1с чогб Магп() ( Бкг1пяорв во = пен Бкг1пдорв()т // создать экземпляр // объекта класса Бвг1пдорв // Инициализировать делегат. Бвгиоб астор = во.вер1асезрасев; всг1пп вкг; // Вызвать методы с помощью делегатов.