Студопедия

КАТЕГОРИИ:

АстрономияБиологияГеографияДругие языкиДругоеИнформатикаИсторияКультураЛитератураЛогикаМатематикаМедицинаМеханикаОбразованиеОхрана трудаПедагогикаПолитикаПравоПсихологияРиторикаСоциологияСпортСтроительствоТехнологияФизикаФилософияФинансыХимияЧерчениеЭкологияЭкономикаЭлектроника


Как реализуются события




Научившись определять класс с членом-событием, пора поближе познакомиться с самим событием и узнать, как оно работает. В классе MailManager есть строчка кода, определяющая сам член-событие:

public event EventHandler<NewMailEventArgs> NewMail;

При компиляции этой строчки компилятор превращает ее в следующие три конструкции:

// 1. ЗАКРЫТОЕ поле делегата, инициализированное null.

private EventHandler<NewMailEventArgs> NewMail = null;

 

// 2. ОТКРЫТЫЙ метод add_Xxx (где Xxx - это имя события).

// Позволяет объектам регистрироваться для получения уведомлений о событии.

[MethodImpl(MethodImplOptions.Synchronized)]

public void add_NewMail(EventHandler<NewMailEventArgs> value)

{

NewMail = (EventHandler<NewMailEventArgs>)Delegate.Combine(NewMail, value);

}

 

// 3. ОТКРЫТЫЙ метод remove_Xxx (где Ххх - это имя события).

// Позволяет объектам отменять регистрацию для получения уведомлений о событии

[MethodImpl(MethodImplOptions.Synchronized)]

public void remove_NewMail(EventHandler<NewMailEventArgs> value)

{

NewMail = (EventHandler<NewMailEventArgs>)Delegate.Remove(NewMail, value);

}

 

Первая конструкция — просто поле соответствующего типа делегата. Оно содержит ссылку на заголовок списка делегатов, которые будут уведомляться при возникновении события. Поле инициализируется значением null, что означает, что нет получателей, ожидающих уведомления о событии. Когда метод регистрирует получателя уведомления, это поле ссылается на экземпляр делегата EventHandler<NewMailEventArgs>, который может в свою очередь ссылаться на дополнительные делегаты EventHandler<NewMailEventArgs>. Когда получатель регистрируется для получения уведомления о событии, он просто добавляет в список экземпляр типа делегата. Ясно, что отказ от регистрации означает удаление соответствующего делегата.

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

Вторая создаваемая компилятором C# конструкция — метод, позволяющий другим объектам регистрироваться на получение уведомления о событии. Компилятор C# автоматически присваивает этой функции имя, добавляя приставку add_ к имени события (NewMail). Компилятор C# также автоматически генерирует код метода, который всегда вызывает статический метод Combine типа System.Delegate. Метод Combine добавляет в список делегатов новый экземпляр и возвращает новый заголовок списка, который снова сохраняется в поле.

Третья и последняя создаваемая компилятором C# конструкция представляет собой метод, позволяющий объекту отказаться от подписки на событие. И этой функции компилятор С# присваивает имя автоматически, добавляя приставку remove_ к имени события (NewMail). Код метода всегда вызывает метод Remove типа System.Delegate. Последний метод удаляет делегат из списка и возвращает новый заголовок списка, который сохраняется в поле.

Заметим также, что оба метода — add и remove — помечены атрибутом MethodImplAttribute (определенным в пространстве имен SystemRuntime.CompilerServices).

Точнее, эти методы помечены как синхронизированные, поэтому они не нарушают безопасность потоков: множество объектов, следящих за событием, может регистрироваться или отменять свою регистрацию одновременно, не нарушая целостность связного списка.

В этом примере методы add и remove являются открытыми, поскольку в соответствующей строке исходного кода событие изначально объявлено как открытое. Если бы оно было объявлено как закрытое, то add и remove, сгенерированные компилятором, тоже были бы объявлены как закрытые. Так что, когда в типе определяется событие, модификатор доступа события определяет, какой код способен регистрироваться и отменять регистрацию для уведомления о событии, но прямым доступом к полю делегата обладает только сам тип. Члены-события также могут объявляться статическими и виртуальными; в этом случае сгенерированные компилятором методы add и remove также будут статическими или виртуальными соответственно.

Помимо генерации этих трех конструкций, компиляторы также генерируют запись с определением события и помещают ее в метаданные управляемого модуля. Эта запись содержит ряд флагов и базовый тип-делегат, а также ссылки на методы-аксессоры add и remove. Эта информация нужна просто для того, чтобы очертить связь между абстрактным понятием «событие» и его методами-аксессорами. Эти метаданные могут использовать компиляторы и другие инструменты, и, конечно же, эти сведения можно получить при помощи класса SystemReflec-tionEventlnfo. Однако сама CLR не использует эти метаданные и во время выполнения требует лишь методы-аксессоры.


Поделиться:

Дата добавления: 2015-04-21; просмотров: 60; Мы поможем в написании вашей работы!; Нарушение авторских прав





lektsii.com - Лекции.Ком - 2014-2024 год. (0.007 сек.) Все материалы представленные на сайте исключительно с целью ознакомления читателями и не преследуют коммерческих целей или нарушение авторских прав
Главная страница Случайная страница Контакты