Существует следующий шаблон, который используется, чтобы избежать состояния гонки при поднятии событий в случае, если другой поток не подписывается из MyEvent, делая его нулевым.
class MyClass
{
public event EventHandler MyEvent;
public void F()
{
EventHandler handler = MyEvent;
if(handler != null)
handler(this, EventArgs.Empty);
}
}
в противоположность неправильному способу его выполнения, который склонен к этому состоянию гонки:
class MyClass
{
public event EventHandler MyEvent;
public void F()
{
if(MyEvent != null)
MyEvent(this, EventArgs.Empty);
}
}
Мой вопрос заключается в том, что System.Delegate
является ссылочным типом: в случае, если MyEvent не равен null, как получилось
EventHandler handler = MyEvent;
похоже, скопирует свой список вызовов вместо получения ссылки.
Я ожидал бы, что с делегатом MyEvent, назначенным переменной "обработчик", после того, как кто-то изменит MyEvent, будет также изменен объект, который ссылается на обработчик.
Очевидно, что это не так, иначе этот отличный шаблон не будет работать.
Я изучил исходный код .NET и до сих пор не смог найти ответ (возможно, там, но я искал около часа и не мог найти его, так что я здесь). Я также прочитал, что спецификация языка С# должна сказать о событиях и делегатах, но это не касается этого вопроса.
Спасибо за ваше время.