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

Имя функции и ее тело произвольны. Здесь мы решили лишь сообщить о наступлении события. Если после этих изменений вы запустите приложение, затем дважды щелкните по указателю времени в правом нижнем углу панели задач и, даже не изменяя даты и времени, просто нажмете кнопку OK диалога Date/Time Properties, то в окне нашего консольного приложения тотчас же появится строка текста:

System time changed:  System.EventArgs

Она свидетельствует о том, что наше приложение получило и обработало сообщение, которое было «опубликовано» (published) объектом SystemEvents в момент возникновения события. Используя новую терминологию, этот факт можно объяснить тем, что мы вовремя подписались (subscribed) на получение публикуемого события.

Чтобы убедиться в том, что вы поняли логику обработки событий, попробуйте сформулировать последовательность шагов, которые надо предпринять, чтобы после однократной обработки события отказаться от подписки, то есть прекратить реагировать на это событие. После того, как вы решите задачу, сравните ваше решение с тем, которое удалось получить мне:

¨  Ввести в класс Test делегата типа EventHandler (точнее, неинициализированную ссылку на него),

¨  Создать и инициализировать этот объект внутри функции Main,

¨  Подписаться на получение уведомлений о событии, добавив своего делегата в список делегатов события TimeChanged,

¨  После обработки первого события отказаться от подписки, убрав делегата из списка абонентов.

Главная идея решения состоит в следующем. Для того, чтобы впоследствии мы смогли отказаться от подписки, надо запомнить делегата. В первом варианте мы не делали этого, да и самого делегата не создавали, а просто добавили адрес нашей функции в список делегатов события TimeChanged. Это возможно только в случае, если сигнатура функции совпадает с сигнатурой делегата.

public static EventHandler eh; // Объявляем ссылку на делегата в классе Test

static void Main()

{

eh = new EventHandler(MyTimeHandler); // Создаем и инициализируем его

SystemEvents.TimeChanged += eh;

}

public static void MyTimeHandler(object sender, EventArgs e) // Эта функция будет вызвана делегатом

{

Console.WriteLine("\n\nSystem time has been changed:  " + e);

SystemEvents.TimeChanged -= eh; // Удаляем своего делегата из списка делегатов события

}

Модель наблюдателя-подписчика

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

namespace TimeEvents

{

// Делегатный тип, несущий информацию о событии

public delegate void QuantumHandler (object clock, QuantumEventArgs args);

public class QuantumEventArgs : EventArgs // Класс, определяющий информацию о событии

{

public readonly int hour, minute, second;

public QuantumEventArgs (int h, int m, int s)

{

hour = h; minute = m; second = s;

}

}

После этого надо создать наблюдателя, который периодически генерирует событие, запускающее делегата(ов).

public class Clock     // Наблюдатель (Observer or Event Publisher) возбуждает событие

{

public event QuantumHandler QuantumPassed;

public void Run()

{

while (true)

{

Thread.Sleep (3000);

DateTime dt = DateTime.Now;

QuantumEventArgs info = new QuantumEventArgs (dt.Hour, dt.Minute, dt.Second);

if (QuantumPassed != null)  // Check if there are any Subscribers

QuantumPassed (this, info);

}

}

}

Класс, реализующий функциональность Подписчика, должен реагировать на событие и использовать информацию, несомую делегатом.

public class SubscriberOne // Подписчик получает уведомления о событии и выводит их на экран

{

private QuantumHandler handler;

public SubscriberOne (Clock clock)