Реализация событий на C # (статьи против reflector)

#c# #events

#c# #Мероприятия

Вопрос:

тип события публичного класса { обработчик событий публичного события> NewEvent;

     public void SmthHappened(string data)
    {
        MyEventArgs<Object> eventArgs = new MyEventArgs<Object>(data);
        OnNewEvent(eventArgs);
    }

    private void OnNewEvent(MyEventArgs<Object> eventArgs)
    {
        EventHandler<MyEventArgs<Object>> tempEvent = NewEvent;

        if (tempEvent != null)
        {                
            tempEvent(this, eventArgs);
        }
    }
}
  

Я ожидал, что компилятор C # переведет новое событие следующим образом:

 private EventHandler<MyEventArgs<object>> _newEvent;

public event EventHandler<MyEventArgs<object>> NewEvent
{
    [MethodImpl(MethodImplOptions.Synchronized)]
    add
    {
    _newEvent = (EventHandler<MyEventArgs<object>>)Delegate.Combine(_newEvent, value);
    }
    [MethodImpl(MethodImplOptions.Synchronized)]
    remove
    {
    _newEvent = (EventHandler<MyEventArgs<object>>)Delegate.Remove(_newEvent, value);
    }
}
  

, но отражатель говорит, что это реализовано таким образом:

 public event EventHandler<MyEventArgs<object>> NewEvent
{
    add
    {
        EventHandler<MyEventArgs<object>> handler2;
        EventHandler<MyEventArgs<object>> newEvent = this.NewEvent;
        do
        {
            handler2 = newEvent;
            EventHandler<MyEventArgs<object>> handler3 = (EventHandler<MyEventArgs<object>>) Delegate.Combine(handler2, value);
            newEvent = Interlocked.CompareExchange<EventHandler<MyEventArgs<object>>>(ref this.NewEvent, handler3, handler2);
        }
        while (newEvent != handler2);
    }
    remove
    {
        EventHandler<MyEventArgs<object>> handler2;
        EventHandler<MyEventArgs<object>> newEvent = this.NewEvent;
        do
        {
            handler2 = newEvent;
            EventHandler<MyEventArgs<object>> handler3 = (EventHandler<MyEventArgs<object>>) Delegate.Remove(handler2, value);
            newEvent = Interlocked.CompareExchange<EventHandler<MyEventArgs<object>>>(ref this.NewEvent, handler3, handler2);
        }
        while (newEvent != handler2);
    }
}
  

Пожалуйста, smb объясните мне, почему это так?

Ответ №1:

Да: C # 4, в принципе, внес некоторые изменения в эту область. Это делает его потокобезопасным без блокировки. Это не единственное изменение — оно также изменяет способ разрешения ссылок на события, подобные полю, внутри класса: = и -= теперь выполняйте биты «добавить» и «удалить» вместо того, чтобы работать непосредственно с вспомогательным полем.

Обратите внимание, что это изменение влияет на код, скомпилированный с помощью компилятора C # 4, даже для старых фреймворков; также внесены изменения в блокировку, которые влияют только на код, скомпилированный для .NET 4, поскольку в нем используется новый метод ( Monitor.TryEnter(object, out bool) ).

Комментарии:

1. Я просто просматривал декомпилированный исходный код события, скомпилированного с помощью Roslyn (так что C # 6), и я все еще вижу цикл do … while с CompareExchange. Какая версия использовала Monitor. TryEnter()? Вы помните?

Ответ №2:

Ответ на этот вопрос во многом зависит от используемой вами версии. За эти годы она была значительно усовершенствована. Смотрите http://blogs.msdn.com/b/cburrows/archive/2010/03/05/events-get-a-little-overhaul-in-c-4-part-i-locks.aspx

Ответ №3:

То, что вы ожидаете, — это простая, не потокобезопасная реализация. Поле, подобное синтаксису события, всегда обеспечивает потокобезопасный синтаксис (отсюда и версия reflector). Обратитесь к этому artcile для понимания событий и того, как они реализуются.