Шаг 183.
Язык программирования C#. Начала.
Делегаты и события. Знакомство с событиями

    На этом шаге мы рассмотрим понятие события и особенности его использования.

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

    Событие описывается в классе. Как и для других членов класса, для событий можно указывать спецификатор уровня доступа (обычно это public). Затем указывается ключевое слово event. После ключевого слова event указывается имя делегата и затем уже название события. Название события - это имя, которое мы даем члену класса, подобно тому как мы даем имя полю или методу. Делегат, который указывается в объявлении события, фактически определяет "тип" события. Дело в том, что при возникновении события для его обработки могут вызываться экземпляры делегата. В объявлении события мы указываем имя делегата, экземпляры которого могут вызываться для обработки события.

    Таким образом, шаблон объявления события (являющегося открытым членом класса) выглядит следующим образом:

  public event делегат событие;

    Например, рассмотрим такое объявление:

  public event MyDelegate MyEvent;

    В данном случае объявляется событие MyEvent, являющееся открытым членом класса (ключевое слово public), а для обработки этого события могут вызываться экземпляры делегата MyDelegate.


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

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


Связанные с событием методы, которые вызываются при возникновении события, называются обработчиками события.

    Для добавления ссылки на экземпляр делегата, который будет вызываться при генерировании события, этот экземпляр (ссылка на него) добавляется с помощью оператора += (только сокращенная форма!). Используется команда вида

  событие += экземпляр                . 
На практике вместо ссылки на экземпляр делегата можно использовать ссылку на метод, соответствующий делегату, с которым объявлено событие. То есть можно использовать команду вида
  событие += метод      . 
После выполнения такой команды, если произойдет событие, то автоматически будет вызван соответствующий метод.


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

    Если мы хотим удалить ссылку на экземпляр делегата из события, то для этой цели используется оператор -= (тоже только сокращенная форма!). Ситуация такая же, как и с оператором +=: мы можем использовать команды вида

  событие -= экземпляр 
или
  событие-=метод           . 
То есть вместо ссылки на экземпляр мы можем использовать ссылку на метод.

    Итак, при возникновении события автоматически вызываются экземпляры делегатов, связанные с этим событием. Но как сгенерировать событие? Ответ простой: его нужно вызвать подобно вызову метода. Указываются имя события и круглые скобки - если нужно, то с аргументами. Количество и тип аргументов определяются делегатом, указанным в объявлении события. Важная особенность события связана с тем, что вызвать (сгенерировать) событие можно только внутри класса.

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


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

    На следующем шаге мы продолжим изучение этого вопроса.




Предыдущий шаг Содержание Следующий шаг