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

Так как обычный метод вызывается для какого-то конкретного объекта класса, то он знает с кем работает и ему нет необходимости передавать ссылку на объект класса. Коды методов Surname и Firstname при этом проще, чем необходимо при вызове статических методов. Статический метод не привязан ни к какому объекту и для того, чтобы он все-таки воздействовал на какой-то конкретный объект, ему надо передать ссылку на него. В связи с этим, нам придется изменить сигнатуру делегата. Замените объявление делегатного типа.

public delegate void ManDelegate (Man m); // Теперь делегатные функции требуют параметр

Подправьте методы Firstname и Surname так, чтобы они работали в статическом варианте.

public static void Firstname (Man m)

{

int n = m.name.IndexOf(' ');

if (n < 0)

n = m.name.Length;

Console.WriteLine("  {0}", m.name.Substring(0, n));

}

public static void Surname(Man m)

{

Console.WriteLine("  {0}", m.name.Substring (m.name.LastIndexOf(' ')+1));

}

Вспомните, что указатель или ссылку, как и любую другую переменную, можно передавать в качестве параметра функции. То же можно делать и с делегатом. Введите в состав класса ManTest метод HandleMen, который будет проходить по всему списку объектов men (типа ArrayList) и выполнять для каждого из них те действия, которые приписаны делегату (читай, статические методы класса Man).

public void HandleMen (string title, ManDelegate func)

{

Console.WriteLine(men.Count == 0 ? "\nList is empty\n" : title);

foreach (Man m in men)

func(m);        // Запуск делегатной функции с параметром

}

Обратите внимание на второй парамер функции HandleMen. Он имеет тип делегата (приближенно — указателя на функцию). Если мы вызовем HandleMen и передадим ей в качестве второго параметра делегата, начиненного адресом Firstname, то мы увидим список имен, а если передать делегата, настроенного на функцию Surname, то будут выведены фамилии. Теперь замените обе ветви переключателя в методе Show (мы приведем лишь одну).

case 'f': HandleMen("List of Man Names:", new ManDelegate(Man.Firstname)); break;

Запустите и все должно работать так же как и ранее. Более того, почувствовав уверенностьв делегатной арифметике, мы можем управлять делегатами самым произвольным образом. C помощью операции вычитания можно удалять задания из списка, существующего в данный момент. Например, вы можете опробовать такую версию:

case 'f':

ManDelegate

f = new ManDelegate(Man.Firstname),

s = new ManDelegate(Man.Surname),

d = f + s;

d += f + s;

HandleMen("List of men:", d);

d -= f + s + f;       // Корректируем список заданий делегата

HandleMen("List of men:", d); // Вновь просим выполнить все задания

break;

Она выведет пять строк текста для каждого объекта из списка «людей». Четыре — как и в предыдущем случае, а пятую — при запуске скорректированного делегата.

События

События во всех языках .NET Framework играют весьма важную роль. В концептуальной схеме объектно-ориентированного подхода к разработке систем они используются для реализации функций наблюдателя (observer) — объекта, следящего за изменением состояния каких-то других избранных объектов системы, или, как иногда говорят, объекта «слушающего» сообщения о событиях. Механизм событий настолько прост, что его легко применить для реализации модели наблюдателя.

Событие ассоциируется с сообщением о нем. Объект-источник генерирует сообщение о событии и все зарегистрированные объекты-получатели или слушатели (listeners) получают его. Сообщение может быть создано как операционной системой при наступлении какого-то реального события (нажата кнопка), так и любой программой, когда того требует логика ее алгоритма. В любом случае механизм обработки событий одинаков.