Новые средства языка. Индексаторы. Делегат на основе обычного метода класса. Делегаты на основе класса MulticastDelegate, страница 6

Теперь рассмотрим способность делегатов запускать последовательную цепочку вызовов, например, последовательно вызвать функции Firstname и Surname. Весьма полезно попробовать сделать это самостоятельно с помощью документации. Перед тем, как вы начнете, подскажу, что для обеспечения последовательности или цепочки вызовов используется класс, который является производным от класса Delegate. Он определен как:

public abstract class MulticastDelegate : Delegate

В качестве второй подсказки используйте тот факт, что такие делегаты умеют аккумулировать ссылки, помещая их в свой внутренний динамический связанный список. Для них определены операции + и –, которые вставляют и удаляют из списка ссылки на вызываемые функции. Кроме указанных ссылок, делегат имеет специальный список (invocation list), определяющий очередность запуска функций. Интересно, что в этом списке ссылки (в действительности, адреса функций) могут повторяться. В любом случае функции из списка вызываются поочередно и в той последовательности, в которой он был создан. Замените код одной из ветвей переключателя switch.

foreach (Man m in men)

{

d = new ManDelegate (m.Firstname) + new ManDelegate (m.Surname);

d();

}

Главным моментом, который иллюстрирует этот фрагмент, является способ создания и техника управления тем перечнем функций, которые делегат должен вызвать. При выборе этой ветви в консольное окно будут выведены по две строки текста (имя и фамилия) для каждого объекта, хранимого в списке men.

Делегаты такого типа (multicast) являются базисом, на котором построено еще одно средство языка С# — события (events). Идея суммирования ссылок, а точнее — коллекционирования их во внутренне поддерживаемом списке (типа TO DO), используется при реализации обработки событий. С помощью этого механизма классы могут подписаться на получение оповещений о событиях, происходящих в системе (напоминает подписку на газеты). И это происходит точно таким же образом, то есть добавлением ссылок во внутренний список функций-обработчиков. Мы рассмотрим эту технологию позже, а сейчас отметим, что идея суммирования обработчиков событий весьма эффективно работает в оконных приложениях. Например, вы можете подписать элемент управления, расположенный на форме, на оповещение его о всех тех событиях, которые, как вы считаете, имеют к нему отношение.

Для того, чтобы убедиться в возможности повторять ссылки в том списке действий, которые должен выполнить делегат, вы можете во фрагмент, приведенный выше, добавить такую строку:

d += new ManDelegate (m.Firstname); // Добавляем еще один «пункт» в список заданий делегата

В консольное окно при этом будет выведена последовательность: имя, фамилия и (вновь) имя объекта. Вызов всех функций из списка, который хранит делегат, можно поизвести с помощью метода DynamicInvoke класса Delegate. Такой способ выглядит менее изящно, но вы должны знать о его существовании. Замените в последнем фрагменте одну или обе строки d(); на:

d.DynamicInvoke (null);

и запустите программу. Она должна работать так же, как и раньше. Параметр null соответствует тому факту, что сигнатура методов, вызываемых делегатом, не содержит входных параметров. Если задействовать еще несколько методов, унаследованных от делегатных классов, то ветви функции Show можно переписать в еще более замысловатом виде.

case 'f':

foreach (Man m in men)

{

ManDelegate[] a = { new ManDelegate(m.Firstname), new ManDelegate(m.Surname)};//Массив делегатов

d = (ManDelegate)Delegate.Combine(a); // Формируем список заданий делегата d

d.DynamicInvoke (null);        // Запускаем список заданий делегата

Console.WriteLine (d.Target);     // Выводим объект, ссылку на который хранит делегат

}

break;