Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

When can the GC collect a Lambda that was hooked to an Event?

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?

like image 600
Martze Avatar asked Oct 31 '22 19:10

Martze


1 Answers

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.

like image 160
Evk Avatar answered Nov 10 '22 16:11

Evk