views:

283

answers:

2

Ted Faison in a podcast on event-based software design mentioned that "sender" and "self" objects in .NET, C++ and Java event statements such as:

private void Button_Click(object sender, RoutedEventArgs e)

are a misnomer since e.g. in the above example "sender" is not really the object which produced the event but a proxy, since you wouldn't want to couple your applications that tightly.

Did I understand him incorrectly (since when I debug it, "sender" does indeed seem to be the original object).

Or is it that common event patterns in these languages (e.g. a common click handler) are tightly coupled but they should be more decoupled, e.g. in composite applications.

He also mentioned that e.g. you shouldn't make inherit from EventArgs since it leads to an explosion of classes, one per event, which only transport a few variables. Many times in his opinion, you can just send a string for instance. He mentioned that this opinion is the opposite of what Microsoft Patterns and Practices suggests.

Any thoughts on these areas?

+1  A: 

First - the 'sender' will hold a reference to the button you clicked. If you have multiple buttons all hooked to the same event, this is how you see which one of the buttons you hit (if you're not passing something in the event arguments to read this).

Also I do to some extend agree that writing new eventargs inheriting frmo EventArgs can lead to explosion of classes - so use with causion. I like just raising an EventArgs.Empty and then have the code catching the event explicit querying the object that raised the event for the data. What i mean is - once you catch the event, instead of reading the data from the event arguments you go to the object that raised the event and read those of its properties you are interrested in. This makes it easier to just read what you need, but ofcourse - you could find yourself in a situation where those properties changed between the event raised and you reading the properties.

Per Hornshøj-Schierbeck
+1  A: 

In most cases, sender is the Button (or whatever) that raised the event. There are some occasions when this isn't the case - such as a (perhaps lazy) pass-thru event:

class Foo {
   private Bar bar;
   public Foo(Bar bar) {
       this.bar = bar;
   }
   public event EventHandler SomeEvent {
       add {bar.SomeEvent += value;}
       remove {bar.SomeEvent -= value;}
   }
   //...
}

Here, if we subscribe to foo.SomeEvent, we will actually get back the event originated by the Bar instance - so sender won't be foo. But this is arguably because we've implemented Foo.SomeEvent incorrectly.

To be honest, in most cases you don't need to check sender; the main time this is useful is when a number of controls share a handler. You should generally be able to assume the sender is the instance you subscribed to (for the purposes of reference-equality tests).

Re EventArgs - the standard pattern (when creating a new event-type) would recommend you to inherit from this. I don't recommend deviating from this. A minor reason is that it allows you to use EventHandler<T>, but there are other variance reasons too. Besides - sometimes doing what other people expect is reason enough; people expect an EventArgs derived value.

That said - I have done non-standard events before (in MiscUtil's Push LINQ) - but this was already in a very unusual setup, so it didn't feel out of place.

Marc Gravell