C# – Prefered way to declare events

c

I am fairly happy with my understanding of the .NET event model. I think I might be misunderstanding a small nuance of the system.

When I started out putting events into my classes I would use the standard way like so:

public event EventHandler<MyEventArgs> MyEvent;

This meant that anything subscribing to the event would need a method like:

void HandleThatEvent(object sender, MyEventArgs args){...}

Which is nice, but I found that I would rarely care about the sender, so it made a lot of method signatures bloated.

So I switched to declaring my own delegate types

public delegate void MyEventHandler(SomeClass argument);

Which cut down on clutter, but left me with a small problem when it came to writing handlers:

eventImplmentor.MyEvent += HandleThatEvent;
.
.
.
void HandleThatEvent(/*oh, um, what arguments does it take? Intellisense isn't telling me*/)

So I would have to go back to the declaration of the delegate and look and then go back and write them in, or compile it and wait to be told.

So now instead, I'm just using Action, Action<T> or whatever template fits.

public event Action<SomeClass> MyEvent;

So that I can hover over the event and be told what parameters it expects.

My question, after all that: Is there a best practice for declaring events in C#? Should I go back to the EventHandler<T> way, or is Action<T> acceptable?

Best Answer

For simple, internal event handling, there are those that simply use Action or Action<T>, as you are proposing. I tend to use the standard pattern, including the Sender, even for internal events, because you never know when you might later want to expose a class or event, and I would not want the penalty of having to refactor the event method just to make it public.

I do agree with you that the event handling signature is a bit heavier than it should be for simple scenarios, but it is well designed to handle incremental migration as additional event arguments could become necessary over time. Overall, I would stick with the standard pattern, especially since, as you noted, you only get proper IntelliSense support if you do.

For what it's worth, I put some time into this and came up with a different event handling pattern: Event Signature in .NET — Using a Strong Typed 'Sender'?. The goal here was not to remove the Sender, but to make it generically strong typed as TSender instead of weakly typed as System.Object. It works very well; however, one does lose IntelliSense support when you do this, so there is an unfortunate trade-off.

Overall, I would stick with the standard pattern, but it is interesting to think about potentially better ways to do this.