【问题标题】:Where is the Dispose method implemented in the Component class libraryComponent类库中实现的Dispose方法在哪里
【发布时间】:2013-11-22 13:15:23
【问题描述】:

好吧,我正在尝试理解可以通过代码显式完成的内存过程的释放。

我在下面的 MS 线程中看到 Dispose 方法是在 Component 类中实现的。在这里,我有三个疑问。

  1. Component 类派生自 IDisposable,但是,在这个类库中,我发现它没有实现方法 Dispose,甚至看起来都不是“public void Dispose() { }”。但是当我只是编写一个类并声明一个没有任何主体的方法时,它会给我编译时错误说,我应该定义主体或使其抽象。为什么会有这种差异?

  2. 我一般用这种方式,比如“connection.Dispose();”在 finally 块中处理 sqlconnection。我知道,SqlConnection 是从 DBConnection 派生的,而 DBConnection 又是从 Component 派生的。当我查看 Component 类时,我只看到方法“public void Dispose();”的声明那么具体在哪里实现呢?

  3. 我还看到了一些专门实现的代码,类似于下面 MS 网站中给出的代码。他们为 Dispose 状态声明了一个 bool 变量,并有一个新的 Dispose 方法,他们在其中调用对象上的 Component Dispose。他们还对非托管资源使用 Kernel32 方法 CloseHandle。这种方法有什么用?在处理它时,我从未将它用于我的 SqlConnection (这也是一个非托管资源)。

http://msdn.microsoft.com/en-us/library/system.gc.suppressfinalize(v=vs.110).aspx

谁能帮我简单理解一下上面的三个问题。我只是在学习所有这些。谢谢

【问题讨论】:

  • Fwiw,Dispose() NOTHING 与内存有关。
  • @JoelCoehoorn:处理非托管和托管资源并回收内存是我学到的。 MS 网站说“实现 IDisposable 接口的对象可以从 IDisposable.Dispose 方法调用此方法,以防止垃圾收集器在不需要它的对象上调用 Object.Finalize。”
  • 你在哪里看到Component 没有实现Disponse?文档清楚地表明确实如此。 msdn.microsoft.com/en-us/library/…
  • 那你学错了。垃圾收集器负责从对象中清理内存,即使您释放了它。
  • 您只是对 IDE 向您显示有关 .NET 框架中的类(如组件)的信息的方式感到困惑。它没有向您显示源代码,您没有所有 .NET 框架类的源代码。微软有它。它只是向您显示类的“大纲”,只是声明。您在对象浏览器中看到的相同。您自己不会那样编写 C# 代码。其他任何关于 .NET 框架的中间书籍都很好地涵盖了您的问题。

标签: c# .net c#-4.0 interface garbage-collection


【解决方案1】:

首先:

public void Dispose() { }

一个身体 - 它只是一个空的。这里没有区别。实际上,虽然Component.Dispose 是:

public void Dispose()
{
    Dispose(true);
    GC.SuppressFinalize(this);
}

这个想法是你overrideprotected virtual void Dispose(bool disposing) 方法如果你想添加逻辑。

其次,如果你像这样打电话给connection.Dispose(),那么你就做错了。你应该使用using 块:

using(var conn = ...)
{
    conn.Open();
    using(var cmd = conn.CreateCommand())
    {
        // etc etc
    }
    // look ma, no finally
}

您的第三点以及您引用的 MSDN 文章只是您可能实际需要这样做的一个示例。 CloseHandle 方法只是一个非托管资源的说明。这是关键,因为您不使用终结器来清理托管资源 - 只使用未处理的资源。因此,一个涉及非托管句柄的示例是一个简单的借口来说明:

  • 从终结器调用 Dispose(false)
  • override Dispose(bool) 方法
  • 有一些代码(句柄)从终结器和处置(分别,Dispose(false)Dispose(true))中得到清理
  • 有一些代码只在 Dispose(true) 情况下执行 - 即向前处理

【讨论】:

  • 马克,谢谢。是的,我当时正在使用“使用”块。但理想情况下,如果我最终在使用 try/catch 时实现了 Dispose 方法,它与使用“使用”有何不同?有什么区别吗?我认为它只是减少了代码行数和优雅的外观?
  • @Divine 它正在消除出错的机会;这是关于成功的坑。在finally 中进行清理(当它可以通过using 完成时)只是要求错误。
  • 马克,谢谢,我会记住的。但是,我无法弄清楚 Dispose 方法在哪里被提到为 Virtual ,您说“受保护的虚拟 void Dispose(bool disposing)”。如果这是个愚蠢的问题,我很抱歉。我没有在组件类中看到此方法 Dispose 标记为 Virtual。我只是在新学习所有这些概念。
  • @Divine 有两个Dispose 方法;一个public,非虚拟且无参数(实现IDisposable.Dispose 合约);和一个protected virtual,带有一个参数:msdn.microsoft.com/en-us/library/…
  • 马克,非常感谢,是的,我明白了,我很傻,对不起。好吧,随着时间的流逝,我现在正在理解所有这些:) 感谢您帮助我理解,非常感谢。我也在阅读你给我的建议。
【解决方案2】:

首先要明确的是,Dispose() 与内存绝对NOTHING。 IDisposable 模式完全是关于清理非托管资源...也就是说,清理所有除了内存的东西。

Component.Dispose() 记录在这里:

http://msdn.microsoft.com/en-us/library/3cc9y48w.aspx

请注意以下内容,除了:

调用 Dispose 后,必须释放对组件的所有引用,以便垃圾收集器可以回收组件占用的内存。

我们再次看到 Dispose()-ing 对象是与释放内存不同的问题。

SqlConnection 的情况下,有一个继承层次结构在起作用。 Component 类型本身有一个空的 Dispose() 方法(空方法是合法的)。该方法是空的,因为基类本身没有任何需要担心的非托管资源。 SqlConnection 类型覆盖基本实现,因此它将关闭与服务器的连接。

现在让我们谈谈终结器。终结器也与内存无关,只是它们由垃圾收集器调用。终结器的目的是在收集对象时释放非托管(非内存)资源。如果您正在构建一个使用 大量 非托管资源的类,这样就不会有争用或耗尽资源的风险,那么终结器本身就足够了,而 Dispose() 没有任何用处。然而,几乎所有的计算资源都有一定程度的稀缺性,因此您可能不想在释放它们之前等待垃圾收集器。垃圾收集器可能在一段时间内不会收集对象,因此 Dispose() 模式的存在是为了提供一种及时、可预测的方式释放非托管资源的方法。

好消息是,大多数情况下,您无需担心终结器。如果你正在构建一种全新的非托管资源,你只需要实现一个终结器。例如,如果程序中有一个类型通过包装 SqlConnection 类来管理与 Sql Server 数据库的连接,则不需要终结器。这可能是一个新类,但 SqlConnection 类型最终处理释放您的数据库连接。但是,您应该在您的类型中实现或使用 IDisposable,以便它管理的连接将被及时释放。另一方面,如果您正在构建一种全新的数据库引擎来与 Sql Server 竞争,或者要从头开始重新实现 Sql Server 连接协议,那么您将需要一个终结器。

有时,您的 Dispose() 方法需要抑制完成。例如,如果在释放非托管资源后再次尝试释放非托管资源会导致不必要的异常,则您可能会这样做。

我想我已经涵盖了您三个问题的大部分要点,但仍有一些问题需要解决:

它看起来像“public void Dispose() { }”。但是当我只是编写一个类并声明一个没有任何主体的方法时,它会给我编译时错误说,我应该定义主体

那个方法有一个主体。 { } 方法的主体。只是它是空的。

[SqlConnection.Dispose()]实际在哪里实现?

您正在查看 IDE。这仅显示方法声明和基本描述。那里有更多的代码。如果你真的想要它,full .Net source code 是可用的。

他们还对非托管资源使用 Kernel32 方法 CloseHandle。这个方法有什么用?

这只是一种特定于处理特定类型资源的方法。 IDisposable 模式的部分目的是提供一个标准的地方来放置这种东西,这样你作为程序员就不需要知道这些东西来正确地处理一个对象。

【讨论】:

  • 乔尔,我正在阅读您的宝贵意见。但是,当我开始前两行时,恐怕会说,我在上面给出的 MS 网站中看到“// 如果处置等于 true,则处置所有托管”。它说它也会清理托管资源。我还读到,它唯一的 Finalize 仅处理托管资源。但是 Dispose 会清理托管资源和非托管资源。请帮我理解。我想学习。
  • @Divine 记住,该代码由终结器调用,该终结器仅在垃圾收集期间运行。垃圾收集器此时会清理内存,但这只是它自己的一部分。我不知道您在哪里读到 Dispose 清理托管资源,但这是错误的。这真的很简单: 1. 垃圾收集器清理托管资源。时期。别的什么都没有。 2. `Dispose() 应该清理非托管资源,如果你做的一切都正确的话。 3. 如果出现问题,终结器是清理未管理资源的紧急/最后机会。
  • 乔尔,谢谢你,阅读并理解了你的全文,对我帮助很大。今天只有我了解了 finalize 和 dispose。再次感谢你。但是,您能否给我一些托管资源的示例? (因为MS文档说,Dispose可以通过重载方法OPTIONALLY,可以清理托管资源)。还有,为什么在IDE的Component类里面看不到Finalize方法?
  • Joel,补充一点,我还将在 dispose 中执行“Dispose”以及“GC.Collect”,以便它强制回收未引用对象的内存。对吗?
  • @Divine 只有一个托管资源:内存。我质疑你在哪里看到 MSDN 上声称 dispose 可以清理托管资源的文档。它不能。此外,在 dispose 中调用 GC.Collect() 将对您正在处理的对象产生 no effect不要这样做。
猜你喜欢
  • 2019-11-30
  • 2021-04-24
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2020-06-08
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多