Volatile 13 страница
Событие может использоваться в качестве левого операнда в операторах «+=» и «-=» (§7.17.3). Эти операторы используются для присоединения к событию обработчика событий или его удаления соответственно. Модификаторы доступа события определяют контексты, в которых такие операции разрешены. Операторы «+=» и «-=» являются единственно допустимыми операторами для события вне типа, в котором оно объявлено. В связи с этим внешний код может добавлять обработчики к событию и удалять их, однако не может получать или изменять базовый список обработчиков событий. В операциях вида x += y или x -= y (где для события x выполняется ссылка за пределы типа, который содержит объявление x) результат операции имеет тип void (а не значение x с типом x после присваивания). Это правило не допускает непосредственного просмотра базового делегата события внешним кодом. В следующем примере показан порядок вложения обработчиков событий в экземпляры класса Button: public delegate void EventHandler(object sender, EventArgs e); public class Button: Control public class LoginDialog: Form public LoginDialog() { void OkButtonClick(object sender, EventArgs e) { void CancelButtonClick(object sender, EventArgs e) { В этом примере с помощью конструктора экземпляра LoginDialog создается два экземпляра класса Button и присоединяются обработчики событий для событий Click. 10.8.1 События, подобные полям В тексте программы в классе или структуре, содержащих объявление события, некоторые события можно использовать как поля. Для такого использования событие не должно бытьabstract или extern и не должно явно включать объявления_методов_доступа_к_событиям;. Такое событие можно использовать в любом контексте, где разрешено использование поля. Поле содержит делегат (§15), ссылающийся на список обработчиков событий, добавленных к событию. Если обработчики событий не добавлены, поле содержит null. В примере public delegate void EventHandler(object sender, EventArgs e); public class Button: Control protected void OnClick(EventArgs e) { public void Reset() { Событие Click используется как поле внутри класса Button. Как показано в примере, это поле можно проверять, изменять и использовать в выражениях вызова делегата. Метод OnClick в классе Button "вызывает" событие Click. Понятие вызова события совершенно эквивалентно вызову делегата, представленного событием. Поэтому не существует специальных языковых конструкций для вызова событий. Обратите внимание, что вызову делегата предшествует проверка, что делегат не равен null. Вне объявления класса Button член Click может использоваться только с левой стороны операторов += и –=, как в следующем примере. b.Click += new EventHandler(…); В этом примере делегат добавляется к списку вызовов события Click, а в примере b.Click –= new EventHandler(…); делегат удаляется из списка вызовов события Click. При компиляции события, подобного полю, компилятор автоматически создает хранилище для хранения делегата и создает методы доступа для события, добавляющие или удаляющие обработчики событий поля делегата. Чтобы быть потокобезопасными, операции добавления и удаления выполняются при блокировке (§8.12) содержащего объекта для события экземпляра или объекта типа (§7.6.10.6) для статического события. Так, объявление события экземпляра вида: class X можно скомпилировать в нечто, эквивалентное: class X public event D Ev { remove { Внутри класса X ссылки на Ev компилируются в ссылки на скрытое поле __Ev. Имя "__Ev" произвольное; скрытое поле могло бы иметь любое имя или вообще не иметь никакого имени. Аналогично объявление статического события вида: class X можно откомпилировать в нечто, эквивалентное: class X public static event D Ev { remove { 10.8.2 Методы доступа к событиям В объявлениях событий обычно опускаются объявления_доступа_к_событиям, как в вышеприведенном примере Button. В число причин для этого входит случай, когда затраты на хранение одного поля на каждое событие не являются приемлемыми. В таких случаях класс может включать объявления_методов_доступа_к_событиям; и использовать частный механизм для хранения списка обработчиков событий. Объявления_методов_доступа_к_событиям; события указывают исполняемые операторы, связанные с добавлением и удалением обработчиков событий. Объявления методов доступа состоят из объявления_метода_доступа_add и объявления_метода_доступа_remove. Каждое объявление метода доступа состоит из лексемы add или remove, за которой следует блок;. В блоке;, связанном с объявлением_метода_доступа_add, указываются операторы, выполняемые при добавлении обработчика событий, а в блоке;, связанном с объявлением_метода_доступа_remove, указываются операторы, выполняемые при удалении обработчика событий. Каждое объявление_метода_доступа_add и объявление_метода_доступа_remove соответствует методу с одним параметром значения типа события и типом возвращаемого значения void. Неявный параметр метода доступа к событию называется value. Когда событие используется в назначении события, используется соответствующий метод доступа к событию. В частности, если оператором присваивания является +=, используется метод доступа add, а если оператор присваивания -=, используется метод доступа remove. В любом случае правый операнд оператора присваивания используется в качестве аргумента метода доступа к событию. Блок объявления_метода_доступа_add или объявления_метода_доступа_remove должен соответствовать правилам для методов void, описанным в §10.6.10. В частности, операторам return в таком блоке запрещено указывать выражение.
|