Why Do We Have EventArgs Class?


There is an interesting thread on MSDN newsgroups (see “event arguments” thread) about the design of our eventing APIs. The question is why do we even have EventArgs class (which is empty)? Should we just allow the second parameter to the event handlers to be an arbitrary type?


We created EventArgs to make it easier for us to evolve the eventing system over time.


For example, we wanted to be able to add additional data to existing events without having to add more parameters to their corresponding event handlers, which would be breaking to existing clients. For example, we could add a Timestamp property to EventArgs, if we ever decided that we needed it. In other words, the EventArgs as a fixed root of the hierarchy gives us more control over what data is carried with events.


Of course this decision turned out to be costly for some scenarios and the benefits yet to be realized, so maybe not the right choice after all – the time will show. This is an example of how careful you should be when you add complexity/features to your design in the name of “future extensibility”.

Comments (9)

  1. Ben says:

    Just a thought, would it be more convenient for developers if you had made EventArgs an interface insteas (IEventArgs)? This way they have their own inheritance model and still pass their own classes as event arguments. Or would that be too flexible, because then if you ever decided to change the interface, it would require all of those classes to modify themselves as well?

  2. Ben,

    I thought about the IEventArgs approach, but as you noted adding new members would result in a breaking change (a big no-no for broadly used frameworks).

  3. Sounds alot like the runtime exception hierarchy discussions (which seem to have agreed upon "Don’t derive from anything other than Exception" http://blogs.msdn.com/brada/archive/2004/03/25/96251.aspx).

    Same premise: there’s nothing to actually use in an EventArgs object–you must always cast it to something useful–so, it never gets used (other than for a method definition).

    "Object" was labourously added as the root of all, why not use it when not extending it at all?

  4. Yes, it is similar to the exception discussion. And it is another demonstration that anticipating the future is very difficult. In both cases the designer added a feature that was supposed to be useful in the future.

    A much better approach is to design for unexpected future (i.e. make it possible for the API to change without breaking). This relates to such guidelines like: prefer classes over interfaces, use enums instead of Booleans, use protected properties instead of protected fields, and many others.

  5. JD says:

    The main complaint I had about the EventArgs class was the busywork in trying to create subclasses.

    The good thing is that it forced me to design the eventArgs subclass in a minimalist way. And it discouraged me from passing random things (by making it more busywork to create each subclass). So as a forcing function it actually works pretty well.

    Since no one is actually forced to derive from EventArgs it’s still possible to have events that don’t use it, but by making it a guideline there is a very recognizable, stable pattern.

    SO I’m not the biggest fan, but I think it turned out pretty well. I like (object sender, EventArgs e) better than (object, object)!

    BTW, choosing ‘e’ as the canonical param name was just plain horrible. Where were the naming gurus for that one?

  6. Steve Dinn says:

    I always wondered what the point of having two parameters to all the event methods was.  Why not put the Object sender parameter as a member of the EventArgs class?  Is there some reason for the way it is that I’m just not seeing?

  7. Anthony Ekeh says:

    Hi.

      I was wondering… is there a relatively painless way of determing the NAME of

    an event that has just been raised? For example, assuming a single event handler method

    for dealing with dynamically subscribed-to events, aside from distinguishing the culprit control

    that raised the event using sender.ToString(), I also want to know the actual name of the

    event that was raised which had previously been subscribed to using an EventInfo object.

    Anthony

  8. Alessandro says:

    Krzysztof, Very nice, thanks for explaining.

  9. Tutto .NET says:

    The .NET Framework uses delegates extensively for event-handling tasks like a button click event exposed