tl;dr: Why are field-like events implemented as a single delegate field? Wouldn't it be more straight-forward to use a list of delegates, thereby eliminating the null
special case and avoiding all the MulticastDelegate magic?
The usual pattern to raise field-like events (ignoring synchronization issues for the moment) is
if (MyEvent != null)
MyEvent(this, e);
which can be quite confusing (Why do I have a null check for 0 handlers, but no loop for multiple handlers?), until you understand how field-like events are implemented and that MyEvent
refers to an automatic backing field which can contain either null
, a single delegate or a MulticastDelegate holding references to multiple handlers.
On a first glance, this seems to be a strange design choice. In particular, the obvious alternative would be to use a list of simple delegates, which is how the Observer pattern is commonly implemented in languages such as Java. True, the invocation would be slightly longer:
foreach (var handler in MyEvent)
handler(this, e);
but it would be easier to understand (in my subjective opinion) and probably easier to implement (no need for all the delegate multicasting logic).
Obviously, the C# designers thought otherwise. Since they are a bunch of very smart people, there must have been a good reason for it. What is it?
Action<Args>
) whose invocation list is the empty list? They chose that delegate removal (x
minusy
for delegates) will givenull
instead of an instance with empty invocation list in the case where the last item(s) in the list disappears by the removal. Why?MyEvent?.Invoke(this, e);