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
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.