In a C# event handler, why must the “sender” parameter be an object?

后端 未结 12 773
半阙折子戏
半阙折子戏 2020-12-02 08:19

According to Microsoft event naming guidelines, the sender parameter in a C# event handler \"is always of type object, even if it is possible to use a

相关标签:
12条回答
  • 2020-12-02 08:45

    I tend to use a specific delegate type for each event (or a small group of similar events). The useless sender and eventargs simply clutter the api and distract from the actually relevant bits of information. Being able to "forward" events across classes isn't something I've yet to find useful - and if you're forwarding events like that, to an event handler that represents a different type of event, then being forced to wrap the event yourself and provide the appropriate parameters is little effort. Also, the forwarder tends to have a better idea of how to "convert" the event parameters than the final receiver.

    In short, unless there's some pressing interop reason, dump the useless, confusing parameters.

    0 讨论(0)
  • 2020-12-02 08:47

    Well, it's a pattern rather than a rule. It does mean that one component can forward on an event from another, keeping the original sender even if it's not the normal type raising the event.

    I agree it's a bit strange - but it's probably worth sticking to the convention just for familiarity's sake. (Familiarity for other developers, that is.) I've never been particularly keen on EventArgs myself (given that on its own it conveys no information) but that's another topic. (At least we've got EventHandler<TEventArgs> now - although it would help if there were also an EventArgs<TContent> for the common situation where you just need a single value to be propagated.)

    EDIT: It does make the delegate more general purpose, of course - a single delegate type can be reused across multiple events. I'm not sure I buy that as a particularly good reason - particularly in the light of generics - but I guess it's something...

    0 讨论(0)
  • 2020-12-02 08:52

    No good reason at all, now there's covarience and contravarience I think it's fine to use a strongly typed Sender. See discussion in this question

    0 讨论(0)
  • 2020-12-02 08:53

    I think there's a good reason for this convention.

    Let's take (and expand on) @erikkallen's example:

    void SomethingChanged(object sender, EventArgs e) {
        EnableControls();
    }
    ...
    MyRadioButton.Click += SomethingChanged;
    MyCheckbox.Click += SomethingChanged;
    MyDropDown.SelectionChanged += SomethingChanged;
    ...
    

    This is possible (and has been since .Net 1, before generics) because covariance is supported.

    Your question makes total sense if you're going top-down - i.e. you need the event in your code, so you add it to your control.

    However the convention is to make it easier when writing the components in the first place. You know that for any event the basic pattern (object sender, EventArgs e) will work.

    When you add the event you don't know how it will be used, and you don't want to arbitrarily constrain the developers using your component.

    Your example of a generic, strongly typed event makes good sense in your code, but won't fit with other components written by other developers. For instance if they want to use your component with those above:

    //this won't work
    GallowayClass.Changed += SomethingChanged;
    

    In this example the additional type-constraint is just creating pain for the remote developer. They now have to create a new delegate just for your component. If they're using a load of your components they might need a delegate for each one.

    I reckon the convention is worth following for anything external or that you expect to be used outside of a close nit team.

    I like the idea of the generic event args - I already use something similar.

    0 讨论(0)
  • 2020-12-02 08:53

    Generics and history would play a big part, especially with the number of controls (etc) that expose similar events. Without generics, you would end up with a lot of events exposing Control, which is largely useless:

    • you still have to cast to do anything useful (except maybe a reference check, which you can do just as well with object)
    • you can't re-use the events on non-controls

    If we consider generics, then again all is well, but you then start getting into issues with inheritance; if class B : A, then should events on A be EventHandler<A, ...>, and events on B be EventHandler<B, ...>? Again, very confusing, hard for tooling, and a bit messy in terms of language.

    Until there is a better option that covers all of these, object works; events are almost always on class instances, so there is no boxing etc - just a cast. And casting isn't very slow.

    0 讨论(0)
  • 2020-12-02 08:59

    Well, that's a good question. I think because any other type could use your delegate to declare an event, so you can't be sure that the type of the sender is really "MyType".

    0 讨论(0)
提交回复
热议问题