Как видно из этого вопроса: Поднять события С# с помощью метода расширения - это плохо?
Я думаю об использовании этого метода расширения, чтобы безопасно поднять событие:
public static void SafeRaise(this EventHandler handler, object sender, EventArgs e)
{
if (handler != null)
handler(sender, e);
}
Но Майк Розенблюм поднимает эту озабоченность в ответ Джона Скита:
Вам, ребята, нужно добавить [MethodImpl (MethodImplOptions.NoInlining)] атрибут этих методов расширения или ваша попытка скопировать делегировать временную переменную оптимизироваться JITter, с учетом нулевой ссылки исключение.
Я провел несколько тестов в режиме Release, чтобы узнать, могу ли я получить условие гонки, когда метод расширения не отмечен NoInlining:
int n;
EventHandler myListener = (sender, e) => { n = 1; };
EventHandler myEvent = null;
Thread t1 = new Thread(() =>
{
while (true)
{
//This could cause a NullReferenceException
//In fact it will only cause an exception in:
// debug x86, debug x64 and release x86
//why doesn't it throw in release x64?
//if (myEvent != null)
// myEvent(null, EventArgs.Empty);
myEvent.SafeRaise(null, EventArgs.Empty);
}
});
Thread t2 = new Thread(() =>
{
while (true)
{
myEvent += myListener;
myEvent -= myListener;
}
});
t1.Start();
t2.Start();
Я некоторое время запускал тест в режиме Release и никогда не имел исключения NullReferenceException.
Итак, был ли неправильный Майк Розенблюм в своем комментарии, а метод вложения не может вызвать расовое состояние?
На самом деле, я думаю, что реальный вопрос заключается в том, будет ли SaifeRaise быть в виде:
while (true)
{
EventHandler handler = myEvent;
if (handler != null)
handler(null, EventArgs.Empty);
}
или
while (true)
{
if (myEvent != null)
myEvent(null, EventArgs.Empty);
}