Нэш Трей - C# 2010. Ускоренный курс для профессионалов (2010) (1160865), страница 77
Текст из файла (страница 77)
Когда вызывается метод на экземпляре, в начале списка параметров ему передается скрытый параметр, известный как ЬЬ1я. представляющий текущий экземпляр*. Когда производится привязка делегата занрытого экземпляра к методу экземпляра на объекте экземпляра, при вызове метода экземпляра делегат передает этот объект экземпляра как ссылку ЬЬая.
В случае делегатов открытого экземпляра это действие возлагается на то, что вызывает делегат. Таним образом, можно указывать экземпляр объекта для вызова в момент обращения к делегату. Рассмотрим пример. чтобы увидеть, на что зто похоже. Представим, что имеется коллекция типов Епр1оуее и компания.
руководство которой решило в конце года повысить на 1055 зарплату всем сотрудникам. Все объекты енр1оуее содержатся в коллек- Подробнее о гЬ1 я в связи со ссылочными типами и типами значений читайте в главе 4. 290 Глаза )0 ции, и нужно выполнить итерацию по всем сотрудникам, обеспечив повышение зарпла- ты вызовом метода Ешр1оуее. Арр1уйа1зеог. ия1пд Буясеш[ сяьлч Бузсеш.кет1ессьощ оя1лд Буясеш.со11есс1оля.оелег1с; с[е1е9асе чо1с[ Арр1укагяеое1е9ате( Ешр1оуее ешр, Рес1ша1 регселс ) рчЬ11с с1аяя Ешр1оуее ( ргьчасе Ресьша1 яа1агу; роЬ11с Ешр1оуее( Рес1иа1 яа1агу ) ( Гбья.яа1агу = яз1згу; ) рсЬ11с Рестша1 Ба1агу ( Бег ( гегнгл яа1агу) ) роЬ11с чо10 Арр1уааьяеот( Рес(ша1 регсепс ) ( яа1агу *= (1 + регселг)) риЬ11с с1аяя Елсгуроьлс ( ясас1с чо1с[ Маьл() Рьяс<Ешр1оуее> ешр1оуеез = лен Ььяс<Ешр1оуеЕ>(); ешр1оуеея.лс[б( пен Ешр1оуее(40000) ); ешр1оуеея.А<(о( лен Ешр1оуее(65000) ); ешр1оуеея.лас)( лен Ешр1оуее(95000) ); // Создать делегат открытого экземпляра.
ИВЬЬобтп№о ва Ьуреог(кир1оуве).пвтзэвткоа( "Арр1укааэаОЕ", Вьп<)эпду1ааа.роЬ11о ( ВапсИ.пдр1ааэ. 1пэсапов ) [ Арр1укааэапе1еоаае арр1укаьае (Арр1укааэапа1адаае ) Пе1вдасе.огвааепе1адааа( Ьуреоу(дрр1укааэапе1враев), ва ) ) уу Выполнить повышение. Гогеасп[ Ешр1оуее е ьл ешр1оуеея ) ( арр1укаьяе( е, (Ресьша1) 0.10 ); Г/ Вывести значения новой зарплаты на консоль. Роляо1е.нгьсе11ле( е.Ба1агу ); Для начала обратите внимание, что объявление делегата имеет тип Ешр1оуее в начале списка параметров.
Так описывается скрытый указатель экземпляра. чтобы можно было привязать его позже. При объявлении делегата закрытого экземпляра этот параметр Ешр1оуее пропускается. К сожалению, в языке С№ не предусмотрено специального синтаксиса для создания делегатов открытого экземпляра.
Поэтому для создания экземпляра делегата придется воспользоваться одной иэ обобщенных перегрузок Ре1еоаге.сгеагепе1едаге,как показано в примере,и перед тем, как сделать это, следует с помощью рефлексии получить экземпляр МеГЬоб1луо,представляющий привязываемый метод. Делегаты, анонимные функции и события 291 Ключевой момент, который здесь нужно отметить; при создании экземпляра делегата нигде не указывается конкретный экземпляр объекта.
Он не предоставляется вплоть до самого момента вызова делегата. Цикл Рогеас)т показывает, как вызывается делегат и в то же время задается экземпляр для вызова. Несмотря на то что метод Арр1ура1зеОЙ. к которому привязан делегат, принимает только один параметр, вызов делегата требует двух параметров, так что можно указать экземпляр, на котором должен быть выполнен вызов метода. В предыдущем примере показано, как создается и вызывается делегат открытого экземпляра; однако делегат может быть более обобщенным и в широком смысле более полезным. В данном примере делегат объявлен так, что он знает. что должен вызывать метод типа Евр1оуее.
Поэтому в момент вызова можно использовать только экземпляр Евр1оуее или типа, производного от Евр1оуее. Обобщенный делегат можно применять для такого объявления делегата, чтобы тип, на котором он вызывается. не был указан во время объявления . Такой делегат потенциально более полезен. Он позволяет заявить следующее: "Я хочу представить метод, соответствующий данной сигнатуре, который поддерживается любым, пока еще не указанным типом". Конкретный тип, который будет вызван.
должен будет указан только в точке создания экземпляра делегата. Рассмотрим следующую модификацию предыдущего примера: к(в1адаса чсЫ Арр1ука1|епа1едаса<Т>( Т 1пзсапсе, Оес1ва1 рвгсвпс ) Рпв11с с1азз ЕпьгуРо(пп ( зпзк(с чо1к( Макп() 11зс<Евр1оуее> евр1оуеез = пен 11зг<Евр1оуее> О; евр1оуеез.йт(г(( пен Евр1оуее(40000) евр1оуеез.йг(С( пен Евр1оуее(55000) ); евр1оуеез.йт(г(( пен Евр1оуее(95000) Г! Создать делегат открытого экземпляра. Мек)тот)1пбо вь = Суреос(евр1оуее).бепиепцос(( "АРР1уна(зеог", ВьппьпдР1адз.Рив11с В1пг(1пдР1здз. 1пзеапсе )( Арр1ука1запв1адаее<йвр1оуеа> арр1уВаьзе (Арр1ука1заов1едаев<ввр1суаа> ) Ое1адасе.Сзааеапе1едаса( суресе(Арр1уВаьзаое1едаса<йвр1суее>), в1 ) Г! Выполнить повышение. гогеас)т( Евр1оуее е 1п евр1оуеез ) ( арр1унаазе( е, (Ресава1) 0.10 )т !/ Вывести значения новой зарплаты на консоль.
Сппзо1е.иг1пеььпе( е.ба1агу )т Теперь делегат получился намного более обобщенным. Несложно предположить. что он окажется удобным в различных ситуациях. Например, представьте графическую программу, которая поддерживает применение фильтров к различным объектам на холсте. Предположим, что нужен делегат для представления обобщенного типа фильтра, применение которого сопряжено с указанием некоторого процентного значения, задающего степень применения определенного эффекта к объекту. Используя обобщенные делегаты открытого экземпляра, можно реализовать такую общую концепцию. Обобщения рассматриваются в главе 11.
292 Глава 10 События Во многих случаях использования делегатов в качестве механизма обратного вызова может понадобиться просто известить кого-то о наступлении некоторого события вроде щелчка на кнопке в пользовательском интерфейсе. Предположим, что проектируется приложение медиа-проигрывателя. Пте-то в пользовательском интерфейсе имеется кнопка "Р1ау" (Воспроизведение).
В хорошо спроектированной системе пользовательский интерфейс отделен от логики управления с помощью четко определенной абстракции, обычно реализуемой через шаблон Впбйе (Мост). Абстракция облегчает последующее изменение пользовательского интерфейса или, что еще лучше, поскольку этот интерфейс зависит от платформы — облегчает перенос приложения на другую платформу. Например, шаблон Вгтбяе хорошо работает в ситуациях, когда требуется отделить логику управления от пользовательского интерфейса. На заметку! Смысл шаблона Владе, согласно книге Эриха Гаммы (Епсп Ваюгпа), Ричарда Хелма (В1спагб Не)гл), Ральфа Джонсона (Ва)РЬ Зоппвоп) и Джона Влиссидеса (болл Н1!вв!бев) Оезгдп Рзлегпв: Е!етеп(з о/г)еизвЫе ОЬ/есЬОг!ептео Бопигаге (Або)вол-Рго(езв)опа1,1995], заключается в отделении абстракции от реализации, чтобы то и другое можно было менять независимо.
Используя шаблон ВгЫйе, можно облегчить сценарий, при котором изменения, происходящие в ядре системы, не влекут за собой изменений в пользовательском интерфейсе и, что более важно, при котором изменения в пользовательском интерфейсе не требуют изменений в ядре системы. Один распространенный способ реализации этого шаблона предусматривает создание в ядре системы четко определенных интерфейсов, через которые пользовательский интерфейс взаимодействует с системой, и наоборот. Однако в таких ситуациях определение интерфейсных типов является громоздким и далеким от идеала. С другой стороны, делегаты представляют собой блестящий механизм для использования в сценариях подобного рода. С помощью делегата можно сформулировать абстрактные вещи следующим образом: "Когда пользователь пожелает включить воспроизведение, необходимо, чтобы были вызваны зарегистрированные методы, принимающие всю необходимую информацию для выполнения данного действия".
Прелесть заключается в том, что ядро системы не волнует, как именно пользователь укажет пользовательскому интерфейсу о том, что он желает включить воспроизведение. Это может быть щелчок на кнопке или срабатывание какого-то устройства, улавливающего мозговые волны и угадывающего мысли пользователя. Для системы это не имеет значения, и в любой момент можно изменить любой компонент взаимодействия.












