C# Form.Close和Form.Dispose的区别

101

我刚接触C#,查看了之前的帖子但没有找到一个好的答案。

在一个只有一个窗体的C# Windows Form应用程序中,使用Form.Close()还是Form.Dispose()更好?

MSDN说当调用Close时,对象内的所有资源都将被关闭并且窗体将被处理。尽管如此,我在网上还遇到了许多示例使用Dispose而不是Close。

这两种方法有什么优劣势?我们应该在哪些情况下优先考虑其中一种方法?


略有不同的问题,但答案相同,在我看来:即Close和Dispose通常是等效的,只是你可以多次调用Close。 - ChrisW
2
@Chrisw:你也可以多次调用Dispose。 - H H
@ChrisW,Dispose 应该被设计成可以多次运行。http://www.bluebytesoftware.com/blog/PermaLink.aspx?guid=88e62cdf-5919-4ac7-bc33-20c06ae539ae - Steven Evers
让我感到困惑的是,使用 dispose 方法比 close 方法更接近实现我的目标。我原本以为 close 方法会比 dispose 方法更温和一些。 - Pete Kirkham
5
如果你想使用 form.Visible = false;,你可以调用 form.Hide()。实际上,form.Hide() 只是将 this.Visible = false; 设置为了隐藏窗体。 - Dirk Vollmar
关闭一个窗体后,我需要对其进行Dispose操作吗? - Reza Aghaei
8个回答

193

这个MSDN论坛可以告诉你。

Form.Close()发送正确的Windows消息以关闭win32窗口。在此过程中,如果该窗体未以模态方式显示,则会调用Dispose以释放窗体持有的非托管资源。

如果执行form1.Show()Application.Run(new Form1()),则当调用Close()时,将调用Dispose

但是,如果您使用form1.ShowDialog()以模态方式显示窗体,则窗体不会被释放,您需要自行调用form1.Dispose()。我认为这是您唯一需要自行处理窗体释放的情况。


第一版是否包含引用?+1 进行补偿。 - H H
@Dan 第一个版本很糟糕...(抱歉 @Kyra) - jjnguy
13
这与MSDN在http://msdn.microsoft.com/en-us/library/system.windows.forms.form.close%28VS.80%29.aspx中所述有些不同:“当窗体是多文档界面(MDI)应用程序的一部分并且该窗体不可见时,唯一不会在关闭时处理窗体的情况是。在这种情况下,您需要手动调用Dispose以标记窗体所有控件以进行垃圾回收。”然而,通过一个简单的示例,很容易检查模式窗体是否已被处理。 - Dirk Vollmar
关闭窗体后,我需要Dispose该窗体吗? - Reza Aghaei
谢谢解释。不过可能需要修复链接 :) - Losbear

16
作为一般规则,我总是主张明确调用任何提供此方法的类的Dispose方法,可以通过直接调用该方法或将其包装在"using"块中来实现。最常见的情况是,实现IDisposible接口的类是因为它们包装了一些需要释放的非托管资源。虽然这些类应该有作为保障的终结器,但调用Dispose方法将有助于更早地且带有较低的开销释放该内存。
对于Form对象,正如Kyra提到的链接所述,Close方法被记录为代表您调用Dispose,因此您不需要显式调用Dispose。然而,对我来说,这总感觉像是依赖于实现细节。我更喜欢始终调用实现了Close和Dispose方法的类,以防止实现更改/错误,并为清晰起见。一个正确实现的Dispose方法应该安全地被多次调用。

关闭窗体后,我需要Dispose该窗体吗? - Reza Aghaei

8

不调用Close可能会绕过发送一堆Win32消息,这些消息似乎非常重要,但我无法具体告诉您为什么...

Close的好处是它会引发事件(可以取消),以便外部人员(对于表单)可以观察FormClosingFormClosed,并相应地做出反应。

我不清楚是否在仅处理表单时引发FormClosing和/或FormClosed,但我将让您进行实验。


5
如果你丢弃了该表单,那么关闭和已关闭事件将不会被调用。 - matrix
5
在使用模态窗口覆盖 MDI 子窗口时,调用 Dispose 方法会导致窗口闪烁。 - techBeginner

4

这是一个老问题,有一些好的答案,但我想分享一个清晰的答案来回答这个非常流行的问题。


如何在代码中关闭窗体?

  • 您是使用 Show 打开的窗体吗?

    那么,在代码中关闭它,只需调用 Close()

  • 您是使用 ShowDialog 打开的窗体吗?

    那么,通过设置 DialogResult 或调用 Close 来关闭它。

我需要释放窗体吗?

  • 你是用 Show 打开了这个窗体吗?

    不需要。当你通过 Close 或点击 X 关闭窗体时,它会自动释放。

  • 你是用 ShowDialog 打开了这个窗体吗?

    是的,你需要。当你通过 Close、设置 DialogResult 或点击 X 关闭窗体时,如果你不打算重复使用这个窗体,你需要显式调用 Dispose,或者确保你在一个 using 块中创建窗体实例,像这样:

    //form will be disposed after the using block
    using (var f = new MyForm())
    {
        if (f.ShowDialog() == DialogResult.OK)
        {
            //Your logic to handle OK here
        }
    }
    

    如果你想稍后重复使用它,那么在不再需要它时不要忘记显式地 Dispose


1
使用 using 是一个相当不错的方式:
using (MyForm foo = new MyForm())
{
    if (foo.ShowDialog() == DialogResult.OK)
    {
        // your code
    }
}

0

Close() - 可以暂时关闭托管资源,并可以再次打开。

Dispose() - 永久删除托管或非托管资源


4
只有在使用 ShowDialog() 方法显示窗体时,这种说法才是正确的。否则,Close() 方法也会同时释放该窗体。 - Peter Duniho

-1
我刚刚尝试了一下使用VS诊断工具,我调用了this.Close()然后Formclosing事件触发。然后当我在Formclosing事件的结尾调用this.Dispose()时,在其中处理了许多其他对象时,它会使清理变得更加顺畅。

-1
如果你在你的窗体中使用 form.close() 并设置你的窗体的 FormClosing 事件,其中在这个事件中再次使用 form.close(),你会进入无限循环并出现 Argument out of range 错误。解决方案是在 FormClosing 事件中将 form.close() 更改为 form.dispose()。我希望这个小提示对你有所帮助!

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接