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

{

clock.QuantumPassed += new QuantumHandler (SubscriberOne_QuantumPassed);

handler = new QuantumHandler (ShowMoney_QuantumPassed);

handler += new QuantumHandler (ShowEx_QuantumPassed);

clock.QuantumPassed += handler;

}

public void SubscriberOne_QuantumPassed (object sender, QuantumEventArgs time)

{

Console.Write ("Time: {0}:{1}:{2}", time.hour, time.minute, time.second);

}

public void ShowMoney_QuantumPassed (object sender, QuantumEventArgs time)

{

double bill = 100 * (1 + time.second * 0.18);

Console.WriteLine ("\t\tGrand total:\t{0,8:c}", bill);

Console.WriteLine (("").PadRight(50, '-'));

}

public void ShowEx_QuantumPassed (object sender, QuantumEventArgs time)

{

Console.WriteLine (("").PadRight(20, '!'));

}

}

public class SubscriberTwo   // Второй подписчик. Он ведет журнал событий (пишет сообщения в файл)

{

public SubscriberTwo (Clock clock)

{

clock.QuantumPassed += new QuantumHandler (SubscriberTwo_QuantumPassed);

clock.QuantumPassed += new QuantumHandler (LogMoney_QuantumPassed);

}

public void SubscriberTwo_QuantumPassed (object sender, QuantumEventArgs time)

{

StreamWriter sw = File.AppendText ("LogTime.txt");

sw.Write ("Time: {0}:{1}:{2}", time.hour, time.minute, time.second);

sw.Close();

}

public void LogMoney_QuantumPassed (object sender, QuantumEventArgs time)

{

double bill = 100 * (1 + time.second * 0.18);

StreamWriter sw = File.AppendText ("LogTime.txt");

sw.WriteLine ("\t\tGrand total:\t{0,8:c}", bill);

sw.WriteLine (("").PadRight(50, '-'));

sw.Close();

}

}

public class Test // Класс для демонстрация модели Publisher-Subscriber

{

public static void Main()

{

Clock clock = new Clock();

SubscriberOne show = new SubscriberOne (clock);

SubscriberTwo log = new SubscriberTwo (clock);

clock.Run();

}

}

}

Модель реакции на события, возбуждаемые другим потоком

Рассмотрим задачу расчета электростатического поля пары точечных зарядов вдоль произвольной прямой линии, лежащей в плоскости, проходящей через центры зарядов. Поле рассчитывается по формуле, известной из курса теоретических основ электротехники (ТОЭ).

Особенностью реализации этой задачи является то, что вычисления производятся в отдельном потоке (thread), который постоянно сообщает о ходе вычислений главному потоку (primary thread проекта PlotCharges типа Windows Application). В обработчике уведомления о событии мы постепенно заполняем массив точек графика, который затем будет построен с помощью компонента Plot. Последний реализован в виде отдельного проекта типа Windows Class Library (dll). Массив точек графика объявлен в классе главной формы. На главной форме также расположен элемент типа ProgressBar. Он используется как индикатор хода процесса вычислений. Данные для этого индикатора (процент выполнения задания) поставляет рабочий поток, осуществляющий расчет электрического поля.

Рассмотрим процесс обмена данными между двумя потоками приложения. Он осуществляется с помощью механизма событий. В классе, обслуживающем вторичный поток (назовем его CalcField), мы объявляем свое собственное событие Move, которое будем возбуждать в момент, когда вычислено значение поля в очередной точке линии. На это событие должен среагировать главный поток приложения, то есть класс главной формы (MainForm).

При этом будет вызвана функция (делегат, тождественный событию). О связи делегата с событием должны позаботиться мы. Более точной формулировкой того, что происходит, будет такая. Система вызовет функцию, адрес которой помнит переменная делегатного типа (Move). Ее можно трактовать как событие. Мы реализуем самый простой случай делегатной модели. Делегат (он же является и событием) — просто адрес функции реакции.