tags:

views:

195

answers:

6

I'm probably just being neurotic, but I regularly find myself in situations in which I have class that publishes an event, and I find it convenient to subscribe to this event from within the class itself (e.g. in the constructor), rather than only subscribing from external classes.

This sounds reasonable to me, but I can't help the nagging feeling that it's a poor practice, for the simple reason that I'm always faced with the question: "Why not perform the actions that you'd provide in the event handler in the code which fires the event?"

public class Button
{
   public Button()
   {
      this.Click += someHandler; // bad practice?
   }

   public event EventHandler Click;

   public void HandleInput()
   {
      if (someInputCondition)
      {
         // Perform necessary actions here rather than 
         // subscribing in the constructor?
         this.Click(this, ...);
      }
   }
}

Are there any drawbacks to subscribing to your own events?

+5  A: 

I see no problem with this. But if you handle the events in the same class you could also override the event method:

protected override void OnClick(Eventargs e)
{
   base.OnClick(e);
}

This is more efficient and gives you the power to swallow the event if necessary (simply not calling base.OnClick()).

codymanix
In addition, it allows you to specify whether you want your code to run before any other event handlers or afterwards (or a little bit of both).
Heinzi
In my case, this is my own custom Button class -- there's no specific relevance to that class name; it could be anything. Hence there isn't an override-able OnClick method (unless I have a gaping hole in my C# knowledge of events).
vargonian
@vargonian: Then I would propose that you make one (`protected virtual void OnLoad(EventArgs e);`). If you aren't designing your own `Button` class as supporting inheritance, than just use `private void` instead. As Flagbug points out, doing it this way ensures that you are in control of when the external events are executed (i.e. whether they are executed before your class's internal click handling code or after it).
Brian
The problem mit OnLoad() is that there is no guarantee that is is called only once and you cannot know exactly when it is called.
codymanix
@codymanix: There are several flaws with what you have just said. **A)** It is very easy to prevent `OnLoad` from processing more than once with a simple `bool`. **B)** `OnLoad` would be protected, so calling it more than once is unlikely to be a concern. If you honestly don't trust your users, then make the processing part of it private and call it before or after calling `OnLoad`. **C)** There is no guarantee that an event is only called once and you cannot know exactly when it is called.
Brian
adding a bool variable won't make it threadsafe and the problem is that winforms may call OnLoad multiple times under certain but rare circumstances.
codymanix
+1  A: 

The issue is that “someHandler” will change the state of your object. Do you want this state changing before or after any “external” code is run by the event?

It is not clear at what point the state change will be make if you subscribe to the event, however calling it in “HandleInput()” make it a lot clearer when it will be called.

(Also it is more normal to call “HandleInput()”, “OnClick” and make it virtual so sub classes can override it)

After saying the above, normally there is no great harm in subscribing to your own event; in UI classes that represent forms it is very common, otherwise it tend to “surprise” a lot of people that read your code.

Ian Ringrose
+2  A: 

There's a very exotic problem due to internal optimization when doing this. Due to the optimization adding/removing event handlers is not thread safe. It only applies to events that are used by the declaring type like in your example.

Fortunately this has been changed with 4.0, but if you're on previous version, you could experience this.

Brian Rasmussen
+1 for good point, but this is not be a problem when subscribing in the contractor or for UI controls (that are also single threaded)
Ian Ringrose
@Ian: I think very few people will encounter this subtle bug, but the few who do will probably do a lot of head scratching.
Brian Rasmussen
if you subscribe in the ctor of your class's to its own events then it is imposibble to run into threading problems.
codymanix
A: 

if you take the ordinary System.Windows.Form class as an example,
when you want to handle the Form_Load event (using visual studio designer), it is handled in the class of the Form itself !

this.Load += new System.EventHandler(this.Form1_Load);

 private void Form1_Load(object sender, EventArgs e)
 {
 }

so i think it is not a problem at all !!.

Nour Sabouny
but you don't expect anyone external from you class to hook these events when you are creating a UI form. So this is a **very common** "specal case".
Ian Ringrose
Why do people wrap the event handler in `new System.EventHandler`?? Simply `this.Load += this.Form1_Load` seems much nicer to me...
Domenic
Yes, you can do this. However, it strikes me as cleaner to just override the `OnLoad` function.
Brian
+1  A: 

If your button class should be the first which receives the click event, you should write your code in the event method, eg.:

protected virtual void OnClick(EventArgs e)
{
    //insert your code here

    if(this.Click != null)
    {
        this.Click(this, e);
    }
}

but if it's not necessary that your class is the first reciever, you can subscribe to the event normally.

Flagbug
+1: One thing I've noticed in `System.Windows.Forms` is that generally, any event found in a UI class has a matching protected function, e.g. `protected virtual void OnLoad(EventArgs e);` and `public event EventHandler Load;` . A similar technique is used in other places within the framework.
Brian
Yes, this is because otherwise you can't ensure that the derived class is the first receiver of the event. With this technique you can simple ovveride the OnLoad method, write your custom code in it and then call the base.OnLoad method, so that the event gets fired.
Flagbug
+4  A: 

This sounds reasonable to me, but I can't help the nagging feeling that it's a poor practice, for the simple reason that I'm always faced with the question: "Why not perform the actions that you'd provide in the event handler in the code which fires the event?"

To answer that question, consider partial class scenarios. Suppose you have a base type B. You run an automated tool that decorates B by extending it to derived class D. Your tool generates a partial class so that developers consuming D can further customize it for their own purposes.

In that case, it seems perfectly reasonable that the user-authored side of D would want to sign up to be called when events declared by B or the machine-generated side of D are raised by the machine-generated side of D.

That was the scenario we found ourselves in when designing VSTO many years ago. As it turns out, it was not difficult to do this in C# but it was quite tricky to get it all working in VB. I believe VB has made some tweaks to their event subscription model to make this easier.

That said: if you can avoid this, I would. If you're just making an event for internal subscription that seems like a bad code smell. Partial methods in C# 3 help out greatly here, since they make it easy and low-cost for the machine-generated side to call little notification functions in the user-generated side, without having to go to the trouble of publishing an event.

Eric Lippert
Partial methods solved all sorts of issues with generated code, it a shame they were not backported more to dataset etc.
Ian Ringrose