Вопрос относительно значения/ссылочного типа событий
В MSDN я нашел следующее:
public event EventHandler<MyEventArgs> SampleEvent;
public void DemoEvent(string val)
{
// Copy to a temporary variable to be thread-safe.
EventHandler<MyEventArgs> temp = SampleEvent;
Это ссылка?
Если это так, я не понимаю его значения, как когда SampleEvent стал нулевым, так и temp
if (temp != null)
temp(this, new MyEventArgs(val));
}
Ответы
Ответ 1
Это паранойя, связанная с нарезкой. Если другой поток отменил подписку на последний обработчик сразу после того, как вы проверили его для null
, он может стать null
, и вы вызовете исключение. Поскольку делегаты являются неизменными, захват моментального снимка делегата в переменную останавливает это от происходящего.
Конечно, у него есть другой побочный эффект, который вы могли бы (вместо этого) в конечном итоге повысить событие против объекта, который считает, что он уже отписался...
Но подчеркнуть - это только проблема, когда несколько потоков подписываются/отписываются на объект, что является редкостью, а b: не совсем желательно.
Ответ 2
(Из того, что я читал в Essential С# 4.0)
В принципе, из этого кода С#:
public class CustomEventArgs: EventArgs {…}
public delegate void CustomEventHandler(object sender, CustomEventArgs a);
public event CustomEventHandler RaiseCustomEvent;
компилятор будет генерировать код CIL (свободно), эквивалентный следующему С# -коду:
public delegate void CustomEventHandler(object sender, CustomEventArgs a);
private CustomEventHandler customEventHandler; // <-- generated by the compiler
public void add_CustomEventHandler(CustomEventHandler handler) {
System.Delegate.Combine(customEventHandler, handler);
}
public void remove_CustomEventHandler(CustomEventHandler handler) {
System.Delegate.Remove(customEventHandler, handler);
}
public event CustomEventHandler customEventHandler {
add { add_customEventHandler(value) }
remove { remove_customEventHandler(value) }
}
При копировании события вы фактически скопируете private CustomEventHandler customEventHandler
. Поскольку делегат является неизменным, копия не будет затронута при изменении оригинала customEventHandler
. Вы можете попробовать этот код, чтобы понять, что я имею в виду:
string s1 = "old";
string s2 = s1;
s1 = "new"; // s2 is still "old"
Еще одна важная характеристика, связанная с созданным CIL
код состоит в том, что эквивалент CIL ключевого слова event
остается в CIL.
Другими словами, событие - это то, что распознает код CIL
явно; это не просто конструкция С#. Сохраняя эквивалент event
ключевое слово в коде CIL, все языки и редакторы могут предоставить
специальные функции, поскольку они могут распознавать событие как особый
член класса.
Я думаю, вы были смущены главным образом потому, что вы считали, что событие является синтаксисом сахара для класса, верно?