views:

125

answers:

3

I have the following function.

What it does is, given a Control (most likely a windows form) i want to have all of the controls contained that "obey" the Rules ( a function screening the controls i want ) subscribe to an event (lets say KeyDown).

The question is: how do i unsubscribe? Or more importantly, do i need to?

Since i will be using this one on the Load event of forms on the form itself will i really need to unsubscribe if the form closes?

(after some light reading and a little understanding of the GC i suspect i don't need to unsubscribe but I'm not sure)

//an example of using the function
    private void Form1_Load(object sender, EventArgs e)
    {
        MyEventHandler.CreateKeyDownEventHandlers(this);
    }

//the function
    public static void CreateEventHandlers(Control Ctrl)
    {
        foreach (Control c in Ctrl.Controls)
        {
            //bool Rules(Control) a function that determines to what controls'
            //events to apply the handler 
            if ( Rules(c) )
            {
                c.KeyDown += (s, e) =>
                {
                  // do something
                };

            }

            //a control might be a groupbox so we want their contained
            //controls also
            if (c.Controls != null)
            {
                if (c.Controls.Count > 0)
                {
                    CreateEventHandlers(c);
                }
            }

        }
    }

This is my first try with events, delegates, anonymous functions and lambdas so if i did something really stupid tell me.

+2  A: 

First, I think you cannot unsubscribe an anonymous function unless it's assigned to a handler variable and that variable is addded to and then removed from the event.

Whether you need to unsubscribe: Think about the object lifetimes. You create anonymous functions in a static method and attach the to controls of which I assume you control the lifetimes.

When you dispose one of these controls, they will no longer be referencing the anonymous functions and the GC can kill them (the anonymous functions), so you don't need to unsubscribe.

If the situation was reversed and something that was created in the static method referenced the controls, as if a control delegate was added to an event in the static context, then the GC couldn't take care of the controls until the reference to them was removed, which wouldn't happen if it was done in the static method.

Johann Gerell
"First, I think you cannot unsubscribe an anonymous function unless it's assigned to a handler variable and that variable is added to and then removed from the event."I read that as well and if it was necessary to unsubscribe then it would be the way I'd go.If i use it on a windows form with the rule that only TextBoxes get the handler then: when the window closes the textboxes get disposed and then the GC can dispose the anonymous functions. Correct?
ThanosPapathanasiou
after some more research and the helpful answer from Grzenio i think your answer is the correct. Thanks for the help.
ThanosPapathanasiou
A: 

You can unsubscribe from an event by using

yourobject.Yourevent-= YourSubscribedFunction;

This will unsubscribe this function from the event.

About the second part of your question:

You do not need to unsubscribe if the object containing the event is destroyed.

I am not sure what happens if the subscribing object is disposed but my tests indicate that the function is still called, eventhough the object no longer exists.

ClassA a = new ClassA();
using (ClassB b = new ClassB()) // implements IDisposable
{
    b.SubscribeToFoo(a); // b subscribes to FooEvent of ClassA
    a.DoFoo(); // a executes FooEvent
}
GC.Collect(); // Run Garbage Collector just to be sure
a.DoFoo(); // a executes FooEvent

The subscribed method of ClassB is called, eventhough b is disposed.

dbemerlin
The 'b' object still exists, a has a reference to b in its event handler list. That's why it is very important to unsubscribe to events you no longer need. in this case your ClassB could implement/override .Dispose, and unsubscribe its handlers there.
nos
+1  A: 

If you are creating the Form once, and these handlers also once at the beginning, then you don't really need to clean anything.

If you create it multiple times though (e.g. you create the form many times when the user clicks on a button), then you need to be careful. And here the answer depends on what exactly is in the handlers:

c.KeyDown += (s, e) =>
            {
              // do something
            };

In general assigning a delegate to an event can cause a dependency cycle from GC's point of view, e.g. imagine that a Form contains control A, and registers to an event on A. Then the form cannot be disposed until A is disposed, and A cannot be disposed until the form is disposed (because it references the form indirectly through the callback). If you only create the form together with control A then its ok (GC will get rid of both at the same time), but when you create controls A dynamically then you can end-up with memory leak.

Grzenio
"If you create it multiple times" The form will open and close, I won't have multiple instances at the same time which i suspect would be the problem if i understand you correctly.
ThanosPapathanasiou