Form.ShowDialog()和dispose

pdi*_*ddy 9 c# dispose idisposable winforms

如果我有这样的方法:

public void Show()
{
   Form1 f = new Form1();
   f.ShowDialog();
}
Run Code Online (Sandbox Code Playgroud)

即使它超出范围,我仍然需要在表单上调用dispose,这将有资格进行垃圾回收.

从一些测试中,多次调用此Show()..在某些时候,似乎GC收集它,因为我可以看到内存尖峰然后它在某个时间点下降.

从MSDN,它似乎说你必须在不再需要表单时调用dispose.

Ada*_*rth 14

往往会发生的事情是,如果项目具有纯粹的管理资源,则不一定需要调用dispose ,但强烈建议,因为它使处置具有确定性.它并不总是需要(在技术意义上),因为那些托管资源本身现在可能符合GC的条件,或者实际上没有任何东西可以默认处理,而且它是一个可扩展点.

对于非托管资源,Dispose Pattern建议实现一个终结器,它将在GC上调用.如果类型没有实现终结器并且没有调用dispose,则可能(很可能)资源将保持未处理状态.终结器是运行时为清理你的东西而提供的最后一次机会 - 它们也是有时间限制的.

请注意,它不会使GC或托管内存回收具有确定性,处理不是 delete来自C++.处置物品可能距离实际收集很远.但是,在托管世界中,您不关心确定性收集,只关心资源管理 - 换句话说,处理.

也就是说,using如果类型是一次性的,无论是使用托管资源还是非托管资源,我总是确保调用Dispose或使用语句- 这是预期的约定:

public void Show()
{
    using (var f = new Form1())
    {
        f.ShowDialog();
    } // Disposal, even on exceptions or nested return statements, occurs here.
}
Run Code Online (Sandbox Code Playgroud)

更新:

在与Servy讨论之后,我觉得我必须表达这一点,作为我在可能的情况下处理建议的理由.在这种情况下MemoryStream,它显然是一次性类型,但实际上目前不处理任何东西.

就凭这,然而,是依靠实现MemoryStream.如果将其更改为包含非托管资源,则这意味着依赖于MemoryStream无需处理任何内容会成为问题.

在可能的情况下(如果是这样IDisposable),我更愿意依赖公共合同.在这种情况下违反合同意味着我可以安全地避免底层实施变更.


Ser*_*rvy 1

在您的具体示例中,不,它不太可能特别有用。表单不会占用大量资源,因此如果清理部分代码需要更长的时间,也不会导致问题。如果该表单恰好持有用于播放视频的控件,那么它可能实际上持有大量资源,并且如果您确实在 dispose 方法中处置了这些资源,那么它是值得的花时间打电话处理。不过,对于 99% 的表单,它们的 Dispose 方法将为空,并且无论您是否调用它都不会对您的程序产生任何(或任何明显的)影响。

它存在的原因主要是为了能够在 1% 的重要情况下处理资源。

还值得注意的是,当 aForm关闭时,它的Dispose方法已经被调用。如果您想在关闭表单之前释放表单资源,则只需要添加using或 显式调用。Dispose(对我来说这听起来通常是个坏主意)。这很容易测试。只需创建一个具有两种形式的项目即可。让第二个表单将事件处理程序附加到Disposing事件并显示消息框或其他内容。然后,当您创建该表单的实例并显示它(无论是否作为对话框)时,您会发现当您关闭它时,即使您保留“表单”实例并且没有您,消息框也会立即弹出曾经需要添加usingDispose调用。

  • @Servy,“当表单关闭时`Form`已经调用了`Dispose`”——这[似乎](http://stackoverflow.com/a/3097383/1421194) **不正确**:“在此期间处理,*如果表单未以模态方式显示*,则在表单上调用 Dispose。[…]但是,如果您执行 form1.ShowDialog() 以模态方式显示表单,则表单 *将不会被处置,并且您将需要自己调用 form1.Dispose()*。” (2认同)