На этом шаге мы рассмотрим понятие события и особенности его использования.
Представим ситуацию, когда есть некоторая программа, а в этой программе имеется несколько объектов, которые "взаимодействуют" друг с другом. Мы хотим добиться того, чтобы при стечении определенных условий для одного из объектов другие объекты на это "среагировали". Объекты "реагируют" через свои методы. Специфика ситуации в том, что решение о необходимости вызвать метод объекту поступает извне, от другого объекта. И такое сообщение должно генерироваться автоматически (как только "звезды расположились нужным образом"). В принципе, для концептуального решения такой задачи нам пригодились бы экземпляры делегата: с их помощью можно в динамическом режиме устанавливать связи между объектами. Остается открытым вопрос с автоматическим оповещением. И вот в этом случае используется специальный член класса, который называется событием.
Событие описывается в классе. Как и для других членов класса, для событий можно указывать спецификатор уровня доступа (обычно это public). Затем указывается ключевое слово event. После ключевого слова event указывается имя делегата и затем уже название события. Название события - это имя, которое мы даем члену класса, подобно тому как мы даем имя полю или методу. Делегат, который указывается в объявлении события, фактически определяет "тип" события. Дело в том, что при возникновении события для его обработки могут вызываться экземпляры делегата. В объявлении события мы указываем имя делегата, экземпляры которого могут вызываться для обработки события.
Таким образом, шаблон объявления события (являющегося открытым членом класса) выглядит следующим образом:
public event делегат событие;
Например, рассмотрим такое объявление:
public event MyDelegate MyEvent;
В данном случае объявляется событие MyEvent, являющееся открытым членом класса (ключевое слово public), а для обработки этого события могут вызываться экземпляры делегата MyDelegate.
Если в объявлении события убрать ключевое слово event, то фактически получим объявление поля, являющегося ссылкой на экземпляр делегата.
Все это касается формальной стороны - объявления события. Но остается открытым вопрос о том, что с событием можно делать. Есть две концептуальные задачи, которые решаются при работе с событиями. Во-первых, событие можно вызвать (или сгенерировать). Во-вторых, событие можно связать с экземплярами делегата, которые будут автоматически вызываться при генерировании (возникновении) события. Начнем со второй задачи.
Для добавления ссылки на экземпляр делегата, который будет вызываться при генерировании события, этот экземпляр (ссылка на него) добавляется с помощью оператора += (только сокращенная форма!). Используется команда вида
событие += экземпляр .
событие += метод .
При добавлении в событие ссылки на экземпляр делегата или ссылки на метод с помощью оператора += вызывается специальный метод-аксессор. При этом ожидается, что в правой части оператора
+= указана ссылка на экземпляр делегата. Для запоминания этой ссылки выделяется специальная переменная типа делегата. Если вместо ссылки на экземпляр делегата указана ссылка на метод, то
получается, что переменной делегата в качестве значения присваивается указатель на метод. В этом случае автоматически создается экземпляр делегата, который ссылается на метод. Ссылка на этот экземпляр записывается в переменную делегата.
Если мы хотим удалить ссылку на экземпляр делегата из события, то для этой цели используется оператор -= (тоже только сокращенная форма!). Ситуация такая же, как и с оператором +=: мы можем использовать команды вида
событие -= экземпляр
событие-=метод .
Итак, при возникновении события автоматически вызываются экземпляры делегатов, связанные с этим событием. Но как сгенерировать событие? Ответ простой: его нужно вызвать подобно вызову метода. Указываются имя события и круглые скобки - если нужно, то с аргументами. Количество и тип аргументов определяются делегатом, указанным в объявлении события. Важная особенность события связана с тем, что вызвать (сгенерировать) событие можно только внутри класса.
Сгенерировать событие через ссылку на объект класса не получится, даже если событие в классе объявлено с ключевым словом public. Через объект доступны только операции += и -=, с помощью которых в событие добавляются и удаляются ссылки на экземпляры делегата.
Спецификатор уровня доступа в объявлении события определяет наследуемость свойства в производном классе и доступность операций += и -= за пределами класса. В любом случае, если в классе
есть событие, то вызвать (сгенерировать) событие можно только в программном коде этого класса.
На следующем шаге мы продолжим изучение этого вопроса.