GC何时可以收集挂接到Event的Lambda



如果我像这样将Lambda与Event挂钩:

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

在什么条件下可以收集lambda ?如果收集了parentControl,它会被收集吗?可以收集parentControl(假设它已被妥善处理,我没有任何引用它在我的代码)?

编辑:整个代码是在一个静态类。这有关系吗?

当你有这样的问题时,试着不使用匿名方法,看看它需要什么才能工作:

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; }
    }
}

现在您有相同的情况,但没有任何匿名方法。问你的问题- control和parentControl已经相互引用,所以从parentControl到control(通过LambdaClass)添加一个间接引用不会改变情况。parentControl和control(和LambdaClass的实例)都应该被GC收集,当没有其他引用从根(局部,静态等)。. net GC收集循环引用没有问题。

你帮得太多了。lambda需要一个"显示类",这是捕获对控件的引用所必需的。稍后用于取消订阅事件。父控件通过其Dispose事件引用显示类对象,显示类引用控件

所以现在控件和lambda的显示类对象都不能收集,直到父控件可以收集。当您删除lambda时,可以更快地收集控件,而不管父控件的生命周期如何。这就是你想要的,子控件总是在父控件之前死亡。

取消订阅SomeEvent是没有必要的,事件不能保持任何其他对象存活。这种情况非常常见,但这里非常清楚,因为MethodThatHandlesEvent() 必须是一个静态方法。必需的,因为DoSomething()是静态的。

删掉lambda

最新更新