Теперь рассмотрим способность делегатов запускать последовательную цепочку вызовов, например, последовательно вызвать функции 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;
Уважаемый посетитель!
Чтобы распечатать файл, скачайте его (в формате Word).
Ссылка на скачивание - внизу страницы.