让我们假设在Windows窗体中,我开始这样一个长期运行的任务:
ThreadPool.QueueUserWorkItem(new WaitCallback(UpdateDailyTasksChart));
然后,这个函数会运行一段时间,但我会在它完成之前关闭窗口。
private void UpdateDailyTasksChart (object param)
{
//Call Data Access Layer, go get MySQL Data. But I close the Form.
UICallback(chartData); //The Form is closed when this is executed.
}
现在这就是UICallback的作用:
private delegate void UICallbackDel(object chartData);
private void UICallback (object chartData)
{
if (InvokeRequired)
{
this.Invoke(new UICallbackDel(UICallback), chartData);
}
else
{
aButtonOnMyForm.Visible = false; //But the Form has been closed!
}
}
奇怪的是,这段代码不会崩溃。
我在Form_Closed事件中放置了断点,执行。我没有检查Form是否仍然存在,例如,通过类变量声明它。但我的猜测确实如此。
所以问题是:GC只会在我的线程结束时收集表单?或者它会发生什么?
答案 0 :(得分:4)
这里有两点:
ObjectDisposedException
。this
,InvokeRequired
(反过来引用this
)和aButtonOnMyForm
来保存对表单的引用。因此,只要ThreadPool
线程尚未完成执行,您的表单就不符合垃圾回收的条件。这就是代码不会崩溃的原因。 (注意:this
始终可以隐式访问。)从中得出的另一件事是,通常明智的做法是在表单关闭之前从表单中注销外部事件处理程序,以免创建内存泄漏。如果你注册一个lambda表达式或匿名委托,你需要保存对它的引用,以便以后取消注册。简单地复制和粘贴相同的代码是行不通的。
答案 1 :(得分:2)
您可能需要查看this帖子。
基本上,您可能会或可能不会获得ObjectDisposedException
,具体取决于您尝试在表单上调用时GC正在执行的操作。你可以尝试抓住它,但它无法可靠地测试,因此这比任何事情都更糟糕。
答案 2 :(得分:2)
垃圾收集器不关心对象是“关闭”,“处置”还是类似的东西。它只关心对象是否仍然可访问。在您的情况下,仍然可以使用this
(隐式或显式)访问表单。这就是您的应用程序不会崩溃的原因。
当然,如果一个对象被关闭或处置或类似的东西,它就有权抛出ObjectDisposedException
或类似的任何你调用它的方法。但它当然不必这样做。