Как видно из этого вопроса: Вызов событий C # с расширением метод - это плохо?
Я подумываю использовать этот метод расширения, чтобы безопасно вызвать событие:
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);
}
or
while (true)
{
if (myEvent != null)
myEvent(null, EventArgs.Empty);
}