What's the purpose of EventArgs as base class in the event pattern?
Asked Answered
C

1

13

The classic general C# event has these parameters:

(object sender, EventArgs e)

I can implement an event with a more specific signature for the e argument, deriving for EventArgs.

Now, what's the purpose of a base class like EventArgs? I mean... it's empty. No base/abstract/virtual properties, nor fields, or something else.

Why the parameters of a basic event aren't just like below?

(object sender, object eventArgs)

That is, why all the event with some implemented and specific event-args parameter derive it from EventArgs and not from a simple object?

The above question is mirrored with the following one. The event delegate in the generic form is:

delegate void EventHandler<TEventArgs>(object sender, TEventArgs e)

and no restrictions are put on the parameter e. But I would have expected something like where TEventArgs : EventArgs, to be coherent...

Casilde answered 16/5, 2017 at 21:56 Comment(5)
Represents the base class for classes that contain event data, and provides a value to use for events that do not include event data - from the documentation. I believe it's self explanatory.Reader
@FedericoDipuma well, sort of, but object would also work for that... except for the .Empty thingHypoglycemia
@MarcGavell of course you are right. I was just pointing to the fact that, as the documentation itself admits, there is no technical reason for EventArgs. Just inheritance consistency.Reader
This bothers me too. Why should a method signature be based on convention, especially when a) no one seems to know the origin and b) it's not a very good convention? Not only do we have use of object but it's presumed that we want to pass a reference to the source of the event. In many cases the source is irrelevant to start with. But if it's not even strongly typed and could literally be anything (sender could be an int) then I don't see the point. I design events the same way I design any other class - with the methods and arguments I need.Tomsk
Loose coupling is the key. The event handler often lives in code that is far removed from yours, written by a programmer you never met before. You can change the EventArgs type, deriving your own and adding extra fields, that distant code will continue to work without it having to be recompiled.Subconscious
A
9

Object wouldn't preclude value types like int, double, etc. Which would introduce boxing and un-boxing issues. The choice of using a base class over object is a choice to enforce the passing of strongly typed objects throughout an API.

I tend to cringe when I see pervasive use of the object type as it kind of defeats the whole point of using a strongly typed programming language, you might as well go program in javascript, although anyone remotely familiar with javascript will know they are striving towards a strongly typed programming paradigm.

EDIT: To elaborate further on the distinction between an event model passing reference types vs value types. When a delegate handling an event alters the data for an event, which many people frequently do when raising an event, if the data passed were a value type you would then need to start thinking about whether you're changing a copy passed by value or the original reference to the value type, of course you would hope you are altering the original. Enforcing the passing of reference types is a pretty critical design decision in the .NET event model.

Amathist answered 17/5, 2017 at 0:50 Comment(7)
ok, useful answer, but what about the lack of constraints like where TEventArgs : EventArgs that I pointed out? Is that a sign that at a certain point the MS team changed idea about the pattern?Casilde
No. I don't see how this isn't entirely consistent with the pattern. It's clear from the API that MS wants all events in .NET to pass the EventArgs reference type.Amathist
Perhaps if generics had been around in .NET 1.0 instead of EventArgs they might have used where TEventArgs : classAmathist
It used to be where TEventArgs : EventArgs but they removed the restriction when they realized, much like the OP did, that it didn't make much practical sense. The original idea was to make it all inherit EventArgs so that you could subscribe multiple different types of events to a single method, but in reality that was almost never a good idea and now pointless with the availability of lambdas. For super performance sensitive events I have used strongly typed sender and whatever type makes direct sense for the args so firing the event doesn't require creating a short-lived args object.Cismontane
@MikeMarynowski cool, hadn't noticed that change, when did that happen? I guess the only argument for creating an EventArgs structure instead of a primitive like an int is you decide later on you want to pass an int and a string with the event you're going to break a lot more code if you used EventHandler<int> instead of EventHandler<MyEventArgs>... I'd still recommend against EventHandler<object>Amathist
@Amathist I'm not entirely sure but it was a while ago, probably around the release of .NET 4.5? Just a guess though, I can't remember.Cismontane
Not sure when it happened. But, referencesource.microsoft.com/#mscorlib/system/eventhandler.cs has a comment which states: // Removed TEventArgs constraint post-.NET 4Billingsley

© 2022 - 2024 — McMap. All rights reserved.