#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 для понимания событий и того, как они реализуются.