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

Massimiliano Kraus
  • 3,638
  • 5
  • 27
  • 47
  • *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](https://msdn.microsoft.com/en-us/library/system.eventargs). I believe it's self explanatory. – Federico Dipuma May 16 '17 at 22:02
  • 2
    @FedericoDipuma well, *sort of*, but `object` would also work for that... except for the `.Empty` thing – Marc Gravell May 16 '17 at 22:03
  • 1
    @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. – Federico Dipuma May 16 '17 at 22:11
  • 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. – Scott Hannen May 17 '17 at 02:52
  • 1
    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. – Hans Passant May 18 '17 at 00:48

1 Answers1

8

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.

Community
  • 1
  • 1
Mick
  • 6,527
  • 4
  • 52
  • 67
  • 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? – Massimiliano Kraus May 17 '17 at 20:52
  • 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. – Mick May 18 '17 at 00:15
  • 3
    Perhaps if generics had been around in .NET 1.0 instead of EventArgs they might have used `where TEventArgs : class` – Mick May 18 '17 at 00:30
  • 2
    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. – Mike Marynowski Sep 11 '18 at 07:36
  • @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 instead of EventHandler... I'd still recommend against EventHandler – Mick Sep 12 '18 at 09:05
  • @Mick 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. – Mike Marynowski Sep 28 '18 at 18:58
  • 1
    Not sure when it happened. But, https://referencesource.microsoft.com/#mscorlib/system/eventhandler.cs has a comment which states: `// Removed TEventArgs constraint post-.NET 4` – Denxorz Nov 15 '19 at 13:43