When programming events in C#, it is advised to create a delegate in form of:
delegate XEventHandler(object sender, XEventArgs e);
My question is on the first argument of the delegate, object sender
. Does it always have to be a generic object
? Having a sender of type object
always results in code similar to this.
val = ((ConcreteType)sender).Property;
or, even more verbose,
ConcreteType obj = sender as ConcreteType
if (obj != null) { ... }
One argument against strongly typed senders is that other objects can forward the event without worrying about the type. While this might make sense in GUI environments, I am not sure if it could benefit outside a GUI.
What if the class of the sender is always known (at least as an abstract class)? For example, if I am implementing a ListChanged
event in an abstract List
class, and if other classes are going to inherit it (e.g. LinkedList
, ArrayList
), is it all right to define my delegate with a sender of type List
?
delegate ListChangedEventHander(List sender, ListChangedEventArgs e);
Or, would there be a downside of changing the conventional object sender
to a more specific type?
0
At this point, it is mostly a (pretty strong) convention. That is, it will be weird if you write a library that does not follow that convention.
The Event Design Guidelines say:
DO use
object
as the type of the first parameter of the event handler, and call itsender
.
However, you may note that current guidance says that you should not define your own custom delegate for events, but use EventHandler<T>
instead, if you can.
As for the design, I would guess that it also promotes the reuse of event handlers, even in contexts not originally foreseen by the original designer of the event.
6
The reason for the recommendation is that it allows for future changes that do not necessarily require changes to existing code, and especially the public interface.
The event mechanism itself can still be used for “VB6”-style events, but you’ll have to change all existing consumers if you ever need to change the signature (or worse: create new versions of the same events). With the recommended approach, as long as the newer items inherit from the existing ones, you can update the signature without fixing existing code.