在 Form.Dispose() 方法中安全调用
Posted
技术标签:
【中文标题】在 Form.Dispose() 方法中安全调用【英文标题】:Safe to Invoke within Form.Dispose() method 【发布时间】:2016-06-14 15:41:00 【问题描述】:我有一个ApplicationContext
和一个Form
。各种异步通信和定时线程有时可能需要重新启动应用程序,但是在我重新启动之前,我必须手动处理 MyApplicationContext
这需要释放新资源时立即需要的资源过程开始。
在这种情况下,似乎只调用Application.Restart()
并不能足够快地处理资源。
在对MyApplicationContext.Dispose()
的调用中,对base.Dispose(disposing)
的后续调用最终调用了Form.Dispose()
方法,因为这可能源自各种线程,我已经看到发生了跨线程操作异常。
/// MyApplicationContext.requestRestart()
private void requestRestart()
this.Dispose(); // dispose of applicationcontext
Application.Restart();
导致...
/// MyApplicationContext.Dispose(bool)
protected override void Dispose(bool disposing)
/// dispose stuff
base.Dispose(disposing);
导致...
/// MainForm.Dispose(bool)
protected override void Dispose(bool disposing)
/// dispose stuff
base.Dispose(disposing);
可以从任何线程调用。
像这样在Form
UI 线程上 Invoke
被覆盖的 dispose 处理程序是否安全?
protected override void Dispose(bool disposing)
if (this.InvokeRequired)
this.Invoke(new Action(() => Dispose(disposing)));
else
if (disposing && (components != null))
components.Dispose();
base.Dispose(disposing);
【问题讨论】:
【参考方案1】:不,从Dispose()
实现调用Invoke()
是不安全的。
好的,既然我已经说过了:当然,您可能会侥幸逃脱。但这是一个非常糟糕的主意,而且真的会导致真正的问题。
Dispose()
方法应该是简单。它不应该访问托管对象,并且应该快速完成。调用Invoke()
可能会导致不确定的延迟,具体取决于程序中发生的其他情况,甚至是彻底的死锁。
除此之外,Dispose()
方法中的一个重要规则是不访问托管对象。至少,您的实现需要首先检查disposing
,以确保在从终结器调用时不会尝试调用Invoke()
。此外,处置当前用于调用Invoke()
方法的对象也绝对不是一个好主意。如果您确实必须使用跨线程调用,那么正确的方法是检索当前对象的SynchronizationContext
并使用它而不是调用Control.Invoke()
。
但实际上,正确的做法是修复重启逻辑,以便整个处置操作发生在拥有正在处置的对象的 UI 线程中。您的对象不应该负责将执行移动到正确的线程; 使用这些对象的代码应该改为。到您的 Form
类的代码涉及时,您应该已经确保代码在拥有该对象的 UI 线程中执行。
【讨论】:
确实,我是在 侥幸逃脱。我认为将我的requestRestart
方法移动到Form
类中会很容易,这样如果需要跨线程调用,它就会在调用堆栈的底部完成。但是这种情况下,没有办法保证发起重启请求的线程一定是Form
UI线程——比如网络IO到达的时候。
你可以在任何你喜欢的地方发起重启请求,只要你确保在真正处理重启请求之前的清理之前你已经移动到UI线程。即使在那里,您可能会发现使用SynchronizationContext
而不是Form
实例很有用/可取,因为大概Form
实例将作为清理的一部分被处置(即您仍然有调用@ 的问题987654338@ 将在 Invoke()
方法返回之前被释放的对象上)。
我接受了您的好建议,并使用主表单中的SynchronizationContext
。谢谢彼得。我对现在的情况感觉好多了。以上是关于在 Form.Dispose() 方法中安全调用的主要内容,如果未能解决你的问题,请参考以下文章