
- •Делегаты
- •Передача делегатов в методы
- •Пример: решение алгебраических уравнений методом бисекции
- •static double F1(double x)
- •public delegate double Fun(double x); // объявление делегата class Test
- •Возможны и другие способы вызова:
- •Делегат может представлять несколько методов:
- •Реализация паттерна
- •Программисты часто используют одну и ту же схему организации и взаимодействия объектов в
- •Описание класса - источника:
- •Описание классов - наблюдателей:
- •Основная программа:
- •Для обеспечения обратной связи между наблюдателем и источником делегат объявлен с параметром типа
- •Возможные операции с делегатами
- •События
- •Событием может быть нажатие кнопки, выбор команды меню, завершение какой-либо операции и т.
- •События и делегаты
- •EventArgs является классом, базовым для всех классов параметров событий. Классы, производные от EventArgs,
- •Предположим, создается класс Clock, который с помощью события уведомляет классы-подписчики о том, что
- •Описание : public event TimeChangeHandler OnChange;
- •Пример «Симуляция и обработка события ButtonClick».
- •class Program {
Описание классов - наблюдателей:
class ObsA |
// класс-наблюдатель 1 |
{ |
|
string Name;
public ObsA(string name) { Name = name; }
public void Do(object o) // реакция на событие источника (o)
{
Console.WriteLine(" ObsA-" + Name + " : Вижу, что ухнул" + o.ToString());
}
}
class ObsB // класс-наблюдатель 2
{
public static void See(object o) // реакция на событие
{
Console.WriteLine(" ObsB тоже видит, что ухнул" + o.ToString());
}
}

Основная программа:
class Program |
|
|
|
{ |
|
|
|
static void Main() |
|
|
|
{ |
|
|
|
Subj s = new Subj(); |
|
//объект класса-источника |
|
событий |
|
|
|
ObsA o1 = new ObsA("1"); |
|
//объекты |
|
ObsA o2 = new ObsA("2"); |
|
//класса-наблюдателя |
|
// регистрация методов наблюдателей в источнике |
|||
s.Register(new Del(o1.Do)); |
// экземлярного |
||
s.Register(new Del(ObsB.See)); // статического |
|||
s.OPPA(); |
// |
|
инициирование события |
s.Register(new |
|
|
|
s.OPPA(); |
|
|
|
} |
|
|
|
} |
|
|
|
Для обеспечения обратной связи между наблюдателем и источником делегат объявлен с параметром типа object, через который в вызываемый метод передается ссылка на вызывающий объект. Следовательно, в вызываемом методе можно получать информацию о состоянии вызывающего объекта и посылать ему сообщения.
Связь «источник — наблюдатель» устанавливается во время выполнения программы для каждого объекта по отдельности. Если наблюдатель больше не хочет получать уведомления от источника, можно удалить соответствующий метод из списка делегата (пула) с помощью метода Remove или перегруженной операции вычитания, например:
public void UnRegister( Del d ) // удаление делегата
{
dels -= d;
}

Возможные операции с делегатами
Обозначение [d1, d2, d3] подразумевает комбинированный делегат, который состоит из трёх простых именно в таком порядке, т.е. при вызове сначала будет вызван d1, потом d2, а затем d3.
Кроме оператора сложения, экземпляры делегатов могут
объединяться при помощи статического метода
Delegate.Combine.
Операция вычитания также имеет альтернативу в виде статического метода
Delegate.Remove.
События
Событие — это элемент класса, предназначенный для организации реакции объектов, использующих объект данного класса, на различные ситуации, происходящие с этим объектом.
События позволят одному объекту посылать другим объектам уведомления об изменении своего состояния. При этом для объектов, являющихся наблюдателями события, активизируются методы-обработчики этого события.
Обработчики должны быть зарегистрированы в объекте- источнике события (в пуле). Таким образом, механизм событий формализует на языковом уровне паттерн «наблюдатель».
Механизм событий можно также описать с помощью модели «издатель-подписчик»: один класс, являющийся отправителем (sender) сообщения, публикует события, которые он может инициировать, а другие классы, являющиеся получателями (receivers) сообщения, подписываются на получение этих событий.
Событием может быть нажатие кнопки, выбор команды меню, завершение какой-либо операции и т. п. Т.е., если происходит что-то важное, программа должна отреагировать.
Порядок возникновения событий предсказать невозможно. Система ждет возникновения события, а затем предпринимает действия по его обработке. Метод, реагирующий на события, называется обработчиком события (event handler).
В среде GUI любые элементы управления могут вызвать событие. Например, если щелкнуть по кнопке, вызывается событие Click, а если добавить элемент в раскрывающийся список, может быть вызвано событие ListChanged. Реакция на событие является предметом заботы других классов, и она совсем не интересует класс, вызвавший событие. Реагировать должны обработчики случившегося события.
В языке С# любой объект может опубликовать набор событий, а другие классы могут на них подписаться. Когда публикующий класс вызывает событие, все подписавшиеся классы уведомляются об этом.
События и делегаты
Создание события в классе состоит из следующих частей:
•описание делегата, задающего сигнатуру обработчиков
событий;
•описание события – элемента класса
источника(издателя);
•описание метода (методов), инициирующих событие.
Класс-издатель определяет делегат, который должен быть
реализован классами-подписчиками. Когда возникает событие, методы подписчиков вызываются через этот пул этого делегата. Программист объявляет обработчик события как любой другой делегат.
Существует соглашение, по которому обработчики событий в .NET Framework возвращают void и принимают два параметра:
•Первый - это источник события, то есть объект-издатель.
•Вторым параметром передается объект, производный от класса EventArgs.
EventArgs является классом, базовым для всех классов параметров событий. Классы, производные от EventArgs, содержат информацию о возникшем событии.
Обычно достаточно базового класса EventArgs. Но, если с событием связаны дополнительные атрибуты/параметры, они указываются в классе производном от EventArgs.
Событие является свойством класса, опубликовавшего его.
Обработка события выполняется в классах-получателях сообщения. Для этого в них описываются методы- обработчики событий, сигнатура которых соответствует типу делегата.
Каждый объект, желающий получать сообщение, должен зарегистрировать в объекте-отправителе этот метод- обработчик.
Предположим, создается класс Clock, который с помощью события уведомляет классы-подписчики о том, что местное время изменилось (например, увеличилось на одну секунду). Назовем это событие OnSecondChange.
Событие и тип делегата для обработки события определяются следующим образом:
[модификаторы] event тип имя
Например: public event TimeChangeHandler OnChange;
В качестве модификатора указывается ключевое слово abstract, override, static, virtual или один из модификаторов права доступа, в данном случае public.
За модификатором стоит ключевое слово event.
Тип - это делегат, который должен быть связан с событием, в данном случае TimeChangeHandler.
Имя - имя события, в рассматриваемом примере это
OnChange.
Принято начинать имена событий с префикса On.
Описание : public event TimeChangeHandler OnChange;
означает, что OnChange является событием, реализованным с помощью делегата TimeChangeHandler.
Объявление этого делегата выглядит так: public delegate void TimeChangeHandler(
object clock,
EventArgs information);
Здесь объявляется делегат, который указывает, что обработчик события должен возвращать void и принимать два параметра: источник события (объект clock) и объект класса EventArgs.
Если у события нет зарегистрированных подписчиков, оно имеет значение null. Следует убедиться в наличии подписчиков прежде, чем вызывать событие.