События

Press any key to continue

Многоадресные делегаты

Press any key to continue

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

Для создания цепочки вызовов методов необходимо сначала создать экземпляр делегата для одного метода, а затем с помощью операции “ += ” добавить остальные методы. В процессе выполнения кода можно не только добавлять новые методы, но и удалять не нужные с помощью операции ” -= ”.

Многоадресные делегаты должны иметь тип возвращаемого значения void. Это означает, что и методы, представляемые многоадресными делегатами также должны возвращать значение void.

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

По той же самой причине при применении многоадресных делегатов не следует использовать out параметры в коде.

Перепишем код функции Main из предыдущего примера с использованием многоадресного делегата.

static void Main(string[] args)

{

DblOp operations = new DblOp(MathOprt.Add);

operations += new DblOp(MathOprt.Sub);

Prc(operations, 4.0,2.0);

Prc(operations, 9.94,5.45);

}


Результат выполнения программы:

*********

4+2 = 6

4-2 = 2

*********

9,94+5,45 = 15,39

9,94-5,45 = 4,49

С помощью событий приложения Windows в С# получают уведомление, что что-то произошло.

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

Практически события – это автоматическое извещение о каком-то произошедшем действии.

Работа с событиями осуществляется в C# согласно модели «издатель-подписчик».

Класс-издатель, ответственный за инициализацию (выработку) событий публикует событие, и любые классы могут подписаться на это событие. При возникновении события исполняющая среда уведомляет всех подписчиков о произошедшем событии, при этом вызываются соответствующие методы-обработчики подписчиков. Другими словами, событие является специализированной формой многоадресного делегата, которое объявляется следующим образом:

event type_delegate object_name;

Где, type_delegate - тип делегата используемого для поддержки события, а object_name – имя объекта событий.

Класс-издатель определяет событие (многоадресный делегат), а классы подписчики с помощью операции += добавляют методы-обработчики, которые будут вызываться при генерации события.

Платформа.NET требует для всех обработчиков событий следующей сигнатуры кода:

void OnHandler_name(object sender, EventArgs e)

{

// Код для обработки события

}

OnHandler_name - имя метода - обработчика событий. Обработчики событий обязательно имеют тип возвращаемого значения void. Обработчики событий принимают два параметра. Первый параметр - это ссылка на объект, сгенерировавший событие. Эта ссылка передается обработчику самим генератором событий. Второй параметр – это ссылка на объект библиотечного класса EventArgs или производного от него. В производном классе, как правило, определяется дополнительная информация о событии.

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

public delegate void type_delegate (object source, EventArgs e);

Чтобы предоставить возможность подписаться на событие, класс генератора событий должен содержать объект типа указанного делегата, например с именем OnEvnt, с ключевым словом event:

рublic event type_delegate OnEvnt;

Ключевое слово event “подчеркивает”, что объект OnEvnt является специализированной формой многоадресного делегата. Использую операцию “+=”, клиенты могут подписаться на это событие:

gnEvent. OnEvnt +=

new GenEvent. type_delegate (OnHandler_name);

где gnEvent имя класса генератора событий, а OnHandler_name имя функции обработчика события.

При необходимости, для уведомления подписчиков, достаточно в классе генератора вызвать функции обработчики с помощью следующего кода:

OnEvnt(this,e),

где this ключевое слово, указывающее на класс (источник события) в котором содержится этот код, а параметр e содержит информацию о событии.

Ниже представлен пример, в котором генератор события уведомляет подписчика об изменении веса груза транспортного средства:


using System;

namespace sobit

{

//Класс для дополнительной информации о событии

class ChangEvArgs: EventArgs

{

string str; // Название автомобиля

public string Avto

{

get

{

return str+" по сравнению с полуприцепом";

}

}

int change; // Величина изменения веса

public int Change

{

get

{

return change;

}

}

//Конструктор класса

public ChangEvArgs(string name,int chng)

{

str = name;

change = chng;

}

}

// Класс -генератор событий (издатель)

class GenEvent

{

public delegate void DlgEvHandler

(object source,ChangEvArgs e);

public event DlgEvHandler OnEvHandler;//Объявление события

public void UpdateEvent(string str,int change)

{

if(change==0)

return;

ChangEvArgs e =

new ChangEvArgs(str,change);

if (OnEvHandler!= null) //Есть подписчики?

OnEvHandler(this,e); //генерация события

}

}

//Подписчик

class RecEvent

{

//Обработчик события

void OnRecChange(object source,ChangEvArgs e)

{

Console.WriteLine("Вес груза '{0}' был {1} на {2} тонны",

e.Avto,e.Change > 0? "увеличен": "уменьшен",

Math.Abs(e.Change));

}

// в конструкторе класса осуществляется подписка на событие

public RecEvent(GenEvent gnEvent)

{

gnEvent.OnEvHandler += //здесь осуществляется подписка

new GenEvent.DlgEvHandler(OnRecChange);

}

}

class Class1

{

static void Main(string[] args)

{

GenEvent gnEvent = new GenEvent(); //Издатель

RecEvent evAbonent = new RecEvent(gnEvent); //Подписчик

gnEvent.UpdateEvent("грузовика", -2); //Генерация события

gnEvent.UpdateEvent("автопоезда", 4); //Генерация события

}

}

}

Результат выполнения программы:

Вес груза 'грузовика по сравнению с полуприцепом' был уменьшен на 2 тонны

Вес груза 'автопоезда по сравнению с полуприцепом' был увеличен на 4 тонны


Понравилась статья? Добавь ее в закладку (CTRL+D) и не забудь поделиться с друзьями:  



double arrow
Сейчас читают про: