Net framework 5, а также среды Visual Studio 2012 и C#


Этап 3. Определение метода, ответственного



Download 6,27 Mb.
Pdf ko'rish
bet206/658
Sana12.06.2023
Hajmi6,27 Mb.
#950840
1   ...   202   203   204   205   206   207   208   209   ...   658
Bog'liq
CLR via C Programmirovanie na platforme Microsoft NET Framework 4 5 na yazyke C

Этап 3. Определение метода, ответственного 
за уведомление зарегистрированных 
объектов о событии
В соответствии с соглашением в классе должен быть виртуальный защищенный 
метод, вызываемый из кода класса и его потомков при возникновении события. 
Этот метод принимает один параметр, объект 
MailMsgEventArgs
, содержащий до-
полнительные сведения о событии. Реализация по умолчанию этого метода просто 
проверяет, есть ли объекты, зарегистрировавшиеся для получения уведомления о 
событии, и при положительном результате проверки сообщает зарегистрированным 
методам о возникновении события. Вот как выглядит этот метод в нашем классе 
MailManager
:
internal class MailManager { 
...
// Этап 3. Определение метода, ответственного за уведомление 
// зарегистрированных объектов о событии
// Если этот класс изолированный, нужно сделать метод закрытым 
// или невиртуальным
protected virtual void OnNewMail(NewMailEventArgs e) {
// Сохранить ссылку на делегата во временной переменной
// для обеспечения безопасности потоков
EventHandler temp = Volatile.Read (ref NewMail);
// Если есть объекты, зарегистрированные для получения
// уведомления о событии, уведомляем их
if (temp != null) temp(this, e); 
}
... 
}


291
Разработка.типа,.поддерживающего.событие
Уведомление о событии, безопасное в отношении потоков
В первом выпуске .NET Framework рекомендовалось уведомлять о событиях сле-
дующим образом:
// Версия 1
protected virtual void OnNewMail(NewMailEventArgs e) {
if (NewMail != null) NewMail(this, e);
}
Однако в методе 
OnNewMail
кроется одна потенциальная проблема. Программ-
ный поток видит, что значение
NewMail
не равно 
null
, однако перед вызовом 
NewMail
другой поток может удалить делегата из цепочки, присвоив 
NewMail
значение 
null

В результате будет выдано исключение 
NullReferenceException
. Для предотвра-
щения состояния гонки многие разработчики пишут следующий код:
// Версия 2
protected void OnNewMail(NewMailEventArgs e) {
EventHandler temp = NewMail;
if (temp != null) temp(this, e);

Идея заключается в том, что ссылка на 
NewMail
копируется во временную 
переменную 
temp
, которая ссылается на цепочку делегатов в момент назначе-
ния. Этот метод сравнивает 
temp
с 
null
и вызывает 
temp
, поэтому уже не имеет 
значения, поменял ли другой поток 
NewMail
после назначения 
temp
. Вспомните, 
что делегаты неизменяемы, поэтому теоретически этот способ работает. Однако 
многие разработчики не осознают, что компилятор может оптимизировать этот 
программный код, удалив переменную 
temp
. В этом случае обе представленные 
версии кода окажутся идентичными, в результате опять-таки возможно исключение 
NullReferenceException
.
Для реального решения этой проблемы необходимо переписать 
OnNewMail
так:
// Версия 3
protected void OnNewMail(NewMailEventArgs e) {
EventHandler temp = Thread.VolatileRead(ref NewMail);
if (temp != null) temp(this, e);
}
Вызов 
VolatileRead
заставляет считывать 
NewMail
в точке вызова и именно 
в этот момент копировать ссылку в переменную 
temp
. Затем вызов 
temp
осущест-
вляется лишь в том случае, если переменная не равна 
null
. За дополнительной 
информацией о методе 
Volatile.Read
обращайтесь к главе 28.
И хотя последняя версия этого программного кода является наилучшей и тех-
нически корректной, вы также можете использовать версию 2 с JIT-компилятором, 
не опасаясь за последствия, так как он не будет оптимизировать программный код. 
Все JIT-компиляторы Microsoft соблюдают принцип отказа от лишних операций 
чтения из кучи, а следовательно, кэширование ссылки в локальной переменной 
гарантирует, что обращение по ссылке будет производиться всего один раз. Такое 
поведение официально не документировано и теоретически может измениться, 


292
Глава.11 .События
поэтому лучше все же использовать последнюю версию представленного про-
граммного кода. На практике Microsoft никогда не станет вводить в JIT-компилятор 
изменения, которые нарушат работу слишком многих приложений
1
. Кроме того, со-
бытия в основном используются в однопоточных сценариях (приложения Windows 
Presentation Foundation и Windows Store), так что безопасность потоков вообще 
не создает особых проблем.
Для удобства можно определить метод расширения (см. главу 8), инкапсули-
рующий логику, безопасную в отношении потоков. Определите расширенный метод 
следующим образом:
public static class EventArgExtensions {
public static void Raise(this TEventArgs e,
Object sender, ref EventHandler eventDelegate) {
// Копирование ссылки на поле делегата во временное поле 
// для безопасности в отношении потоков
EventHandler temp = Volatile.Read(ref eventDelegate);
// Если зарегистрированный метод заинтересован в событии, уведомите его
if (temp != null) temp(sender, e);
}
}
Теперь можно переписать метод 
OnNewMail
следующим образом:
protected virtual void OnNewMail(NewMailEventArgs e) {
e.Raise(this, ref m_NewMail);
}
Тип, производный от 
MailManager
, может свободно переопределять метод 
OnNewMail
, что позволяет производному типу контролировать срабатывание со-
бытия. Таким образом, производный тип может обрабатывать новые сообщения 
любым способом по собственному усмотрению. Обычно производный тип вы-
зывает метод 
OnNewMail
базового типа, в результате зарегистрированный объект 
получает уведомление. Однако производный тип может и отказаться от пересылки 
уведомления о событии.

Download 6,27 Mb.

Do'stlaringiz bilan baham:
1   ...   202   203   204   205   206   207   208   209   ...   658




Ma'lumotlar bazasi mualliflik huquqi bilan himoyalangan ©hozir.org 2024
ma'muriyatiga murojaat qiling

kiriting | ro'yxatdan o'tish
    Bosh sahifa
юртда тантана
Боғда битган
Бугун юртда
Эшитганлар жилманглар
Эшитмадим деманглар
битган бодомлар
Yangiariq tumani
qitish marakazi
Raqamli texnologiyalar
ilishida muhokamadan
tasdiqqa tavsiya
tavsiya etilgan
iqtisodiyot kafedrasi
steiermarkischen landesregierung
asarlaringizni yuboring
o'zingizning asarlaringizni
Iltimos faqat
faqat o'zingizning
steierm rkischen
landesregierung fachabteilung
rkischen landesregierung
hamshira loyihasi
loyihasi mavsum
faolyatining oqibatlari
asosiy adabiyotlar
fakulteti ahborot
ahborot havfsizligi
havfsizligi kafedrasi
fanidan bo’yicha
fakulteti iqtisodiyot
boshqaruv fakulteti
chiqarishda boshqaruv
ishlab chiqarishda
iqtisodiyot fakultet
multiservis tarmoqlari
fanidan asosiy
Uzbek fanidan
mavzulari potok
asosidagi multiservis
'aliyyil a'ziym
billahil 'aliyyil
illaa billahil
quvvata illaa
falah' deganida
Kompyuter savodxonligi
bo’yicha mustaqil
'alal falah'
Hayya 'alal
'alas soloh
Hayya 'alas
mavsum boyicha


yuklab olish