5

If I hook a Lambda to an Event like this:

static void DoSomething(Control control)
{
    control.SomeEvent += StaticMethodThatHandlesEvent;
    Control parentControl = control.Parent;
    parentControl.Disposed += (sender, args) =>
        {
            control.SomeEvent -= StaticMethodThatHandlesEvent;
        };
}

Under what conditions can the lambda be collected? Will it be collected if the parentControl is collected? Can the parentControl be collected (Assumed it has been properly disposed and i don't have any references to it in my code)?

Edit: The whole code is in a static class. Is this relevant?

4
  • It depends on how anonymous delegate is implemented. Particularly, are there any closures in the lambda's body?
    – Dennis
    Commented Sep 10, 2015 at 6:28
  • I fixed the question, now it is very close to what i do. So i think i only have control inside the anonymous delegate.
    – Martze
    Commented Sep 10, 2015 at 6:30
  • 1
    isn't that kind of redundant? Surely if the parent control is collected, the child will be as well, including the event handler delegates. What are you actually trying to solve? Event handlers only really "leak" when the event survives longer than its handlers - hardly a case for a Control.
    – Luaan
    Commented Sep 10, 2015 at 7:58
  • The MethodThatHandlesEvent is a static method. Isn't there a reference to the Object that the event handler is hooked to?
    – Martze
    Commented Sep 10, 2015 at 8:23

2 Answers 2

1

When you have questions like this, try to do that without anonymous methods and see what is required for it to work:

internal class Program {
    private static void Main(string[] args) {
        DoSomething(new Control() {Parent = new Control()});
    }

    private static void DoSomething(Control control) {
        control.SomeEvent += MethodThatHandlesEvent;
        Control parentControl = control.Parent;
        parentControl.Disposed += new LambdaClass(control).OnDisposed;
    }

    private class LambdaClass {
        private readonly Control _control;
        public LambdaClass(Control control) {
            _control = control;
        }

        public void OnDisposed(object sender, EventArgs e) {
            // if MethodThatHandlerEvent is not static, you also need to pass and store reference to the wrapping class
            _control.SomeEvent -= MethodThatHandlesEvent;
        }
    }


    private static void MethodThatHandlesEvent(object sender, EventArgs e) {

    }

    private class Control {
        public event EventHandler SomeEvent;
        public event EventHandler Disposed;
        public Control Parent { get; set; }
    }
}

Now you have the same situation but without any anonymous methods. Asking your question - control and parentControl already have references to each other, so adding one more indirect reference from parentControl to control (through LambdaClass) does not change situation. Both parentControl and control (and instance of LambdaClass) should be collected by GC when there will be no other references to them from the roots (locals, statics and so on). .NET GC has no problem collecting circular references.

1

You are helping entirely too much. The lambda requires a "display class", necessary to capture the reference to control. Used later to unsubscribe the event. The parent control has a reference to the display class object through its Dispose event and the display class has a reference to control.

So right now both control and the display class object for the lambda cannot be collected until the parent control can be collected. When you delete the lambda then control can be collected much sooner, regardless of the lifetime of the parent. Which is what you want, child controls always die before their parent control.

Unsubscribing SomeEvent just is not necessary, the event cannot keep any other object alive. Very often the case but crystal-clear here since MethodThatHandlesEvent() must be a static method. Necessary because DoSomething() is static.

Just delete the lambda.

Not the answer you're looking for? Browse other questions tagged or ask your own question.