Version (c) is a form of continuation passing, it is not an event at all. It is a wholly different method of control flow, and can be used to express some complex types of control flow that are difficult to express with primitive constructs such as loops and conditionals. For example, it's the basis for asynchrony in C# 5. All await
really does, in essence, is pass a continuation.
It is certainly a valid construct, but the answer to when you should use this for event-driven programming is never, because it's not an event. There is no subscription of any kind; the callback is coupled to method call. You also can't have multiple subscriptions, which you can have with any old event
.
So it comes down a choice between (a) using a plain EventHandler
or (b) using a custom MyEventHandler
with event data. And the answer to that is simple: use a custom event if there is important, transient data associated with the event.
Imagine if you had to query for the cursor position every time you executed a MouseDown
event handler. It would be completely unreliable, because the mouse position could and often would change between the time the event was fired and the time it was handled. On the other hand, an Initialized
event is pretty self-explanatory; it's only going to happen once in the lifetime of an object and there's really not much else to say about it other than "OK, I'm ready!".
So, in summary, (a) use the default EventHandler
when you've got nothing else interesting to say, (b) use a strong-typed EventHandler<T>
when you do, and (c) don't use CPS for event notifications.