Why does MSDN recommend including the sender of an object in delegate declarations?

I read this page , and I noticed how it is said, these are standard recommendations:

The .NET Framework recommendations indicate that the delegate type used for an event must accept two parameters, an "object source" parameter indicating the source of the event, and an "e" parameter that encapsulates any additional information about the event.

I can understand how using an object sender can be useful in some cases, but I could see as opposed to others. For example,

  • What if the class that handles the event does not need to know who fired it? Communication, cohesion and all that.

  • In my case, I already have a reference to the object as a member variable. This is how I sign up for the event. There will be only one instance, so there is no reason to drop the sender object, and not just use a member variable.

  • In my program, the sender object should not be known to clients at all. It is hard to explain what I am doing, but basically I have a class with an internal constructor in the library, which is used by two other classes inside this library. My client classes subscribe to events from these two classes, but initially events that clients should not know are called from this internal call.

  • This confuses event handler clients. Libraries should be clear, and in my case there is no reason to use a sender variable. None. Then why turn it on?

As the saying goes, why does Microsoft indicate that event handlers should follow these guidelines? Isn't that always the best choice?

EDIT: Thanks for all the answers. I decided to go with the majority and use EventHandler<T> for all my events in this library.

+7
source share
7 answers

I think the reason for the template is to provide some consistency. The sender parameter allows you to reuse a single handler for several publishers (buttons, tables).

To indicate your points:

1) just do not use it. This is a common thing, and in fact it will not harm any good practice.

2) that ok, ignore the sender again

3) is in complete contradiction with what you said under 2) ...
And for the rest, this is the same as 1). You can even consider passing null as a sender.

4) "then why turn it on" - there are other use cases that require the sender.


But note that this is just a guide for BCL-validating libraries.
Your case is more like a specific application (rather than a library), so feel free to use whatever parameter scheme you like. The compiler will not complain.

+1
source

You are fighting against the wind, the .NET platform has a certain design, rules and recommendations, and when using it, if you want to use it correctly, you must follow these instructions.

if you use raw delegates, you have all the freedom you want, but as stated above, if you declare a delegate type for an event, you must include the sender object and EventArgs , as well (base or derived class).

if you break these rules, as I said in response to your other question: Should I use EventArgs or a simple data type? , you could potentially be in a situation where your code breaks.

A simple update, when the framework raises the OnClick event in the control, the .NET Framework passes the sender and the EventArgs instance ... if the event does not match, something might break.

If you want complete freedom, use simple delegates, but not events.

+1
source

First of all, it is important to note that leadership is not law.

All hell (or the equivalent of a programmer) will not break if you do not follow the recommendations.

Thus, feel free to modify the signature of your events accordingly.

However, it is also important to know why these recommendations were added to begin with, and one major part of the answers to this question is version control.

Having the following two parts and only those two parts:

  • The source of the event that was introduced as “generic” as possible (note that the event signatures were developed long before the correct generics were introduced into the system, so object is as generic as it might be)
  • Object inheriting from EventArgs

then you develop code that is more resilient to change.

First of all, since you are not allowed to add or remove parameters, all future versions of your event will still only have sender and e .

Secondly, there is a second part with respect to the parameter e . If you decide to change the signature of the event handler in the new version of the class library by changing the type of the parameter e , you should make it more specific by dropping from your current type and passing to the descendant instead.

The reason for this is because existing code that is already processing your current (old) type will still work.

Thus, all the reasoning underlying the guide is as follows:

  • Stay consistent (as others have pointed out)
  • Design for the future (making sure that code written against version X of your class still works when you release version X + 1 without manually modifying this code)

Now, if any of these questions are not worrying about your case, feel free to follow the recommendations.

In fact, you can make an event from Action , and it will work fine.

+1
source

Why? People always ask about it. In this regard, this is approximately a template. By having event arguments packed into a class, you become better at semantics of semantics. Having a common template (sender, e) , it is easy to learn as a signature for all events. I recall how bad it was with Win32 - when the data was in WPARAM versus LPARAM, and soon. The pattern becomes noise, and developers simply assume that event handlers have access to the sender and the arguments of the event.

-Chris Anderson, in Framework Design Guides: conventions, idioms, and patterns for reusable .NET libraries

If you are a .NET developer and you have not read this book, you are missing. This gives you a window;) in the minds of Microsoft.NET Framework designers and many best practices (including the arguments behind them).

(Alternatively, you can run FxCop to make sure these methods are followed.)

+1
source

Recommendations like this allow predictability on the part of the consumer of the event. It also allows you to handle additional scripts that you may never have considered when creating an event, especially if your library is used by third-party developers.

It allows the event processing method to always have the correct instance of the object at hand, as well as basic information about why the event was fired.

0
source

This is just good practice, but you'll be fine until you need to know about an object that had an event or any other information related to the object. I always turn it on, because you never know when you will need it.

My suggestion is to stick to it, it won’t hurt at all.

0
source

There would be nothing wrong, semantically, with event handlers who are interested in where the events came from using the derivative of EventArgs , which included such a field. In fact, there are many situations where it would be cleaner than passing Sender as a separate parameter (for example, if a processor with a keyboard backlight needs to run the Click handler for a button, this event should not be considered raised by the button, but rather raised button on behalf of). Unfortunately, including this information in the EventArgs -derived type would require creating a new instance of the EventArgs -derived type each time an event occurs, even if it could otherwise use EventArgs.Empty . Using a separate parameter to transmit information eliminates the need for each event to instantiate a new object in this general case.

Although it would be possible to have handlers that care about where the event came from, use a parameter for this, and have those that don't care about it, omit the parameter that would require any helper methods and classes that help in handling event subscriptions must have versions for events that either did not include the parameter. The presence of all events takes two parameters, one of which is of type Object and one of which is of type derived from EventArgs , which allows one auxiliary method or class to process all events.

0
source

All Articles