GC何时可以收集挂接到Event的Lambda
本文关键字:Event Lambda 何时可 GC | 更新日期: 2023-09-27 18:12:17
如果我像这样将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