IDisposable是用来做什么的?

22

如果.NET有垃圾回收,为什么你还需要显式调用IDisposable


2
如果您在搜索框中输入IDisposable,就会得到许多现有的答案。 - Daniel Earwicker
6个回答

52

垃圾回收是针对内存的。你需要处理非内存资源 - 文件句柄,套接字,GDI+句柄,数据库连接等。这通常是 IDisposable 类型的基础,尽管实际的句柄可能深藏在一系列引用中。例如,您可能会 Dispose 一个 XmlWriter,它会释放它所引用的 StreamWriter,后者会释放 FileStream 本身持有的文件句柄。


9

在其他评论的基础上再扩展一下:

Dispose()方法应该被调用来处理所有具有非托管资源引用的对象。这些对象的例子包括文件流、数据库连接等。一个基本规则是:“如果.NET对象实现了IDisposable,那么当你使用完对象后应该调用Dispose()。”

然而,还有一些需要注意的事项:

  • 调用dispose并不意味着你控制着对象何时被销毁和内存被释放。GC会代替我们完成这项工作,并且做得比我们更好。
  • Dispose会清除所有原生资源,直到基类堆栈中的最后一个,并调用SuppressFinalize()表示对象已经准备好被回收,不需要进一步工作了。下一次GC运行时它就会把它清理掉。
  • 如果没有调用Dispose,那么GC会发现该对象需要清理,但必须先调用Finalize以确保资源被释放,请求Finalize被排队,GC继续工作,所以没有调用Dispose会强制运行一次GC,在对象被清理之前。这会导致对象被升级到下一个“代”的GC。这可能看起来不是很重要,但在一个内存压力大的应用程序中,将对象升级到较高的GC代可能会将高内存应用程序推向成为一个内存不足的应用程序。
  • 除非绝对必要,否则不要在自己的对象中实现IDisposable。实现不良或不必要的实现可能会使情况变得更糟。一些好的指导可以在这里找到:

    实现Dispose方法

    或者阅读MSDN关于垃圾回收的整个章节


回复:“除非绝对需要”,否则不要实现IDisposable... -在定义接口时要小心 -如果接口的任何实现可能需要处理,则接口应从一开始就是可处理的。否则,所有客户端都需要重构。 - morechilli
我认为关于不必要实现某些内容的警告更针对于Finalize()而非Dispose() - Greg D
1
IDisposable 的目的是提供一种标准方式,让对象知道它们的服务不再需要时。这反过来允许它们通知其他对象,它们曾经使用过这些对象的服务,这些其他对象的服务也不再需要了。关心其服务何时不再需要的对象应该实现 IDisposable。拥有关心自己何时不再需要的其他对象的对象也应该实现 IDisposable,以便将“不再需要”的通知转发给这些内部对象。 - supercat

5

由于对象有时会持有除内存之外的资源,GC会释放内存;IDisposable则是为了释放其他任何资源。


1

因为您想要控制对象持有的资源何时被清理。

看,垃圾回收机制是有效的,但它只会在自己感觉需要的时候才进行,即使这样,您添加到对象中的终结器也只会在2次垃圾回收后才被调用。有时,您希望立即清理这些对象。

这就是IDisposable的用途。通过显式调用Dispose()(或使用using块的语法糖),您可以以标准方式访问对象并使其自我清理(例如,您可以实现自己的cleanup()调用并显式调用它)

您希望立即清理的示例资源包括:数据库句柄、文件句柄、网络句柄。


1

0

IDisposable 接口通常在资源方面进行描述,但是大多数这样的描述未能真正考虑到"资源"的真正含义。

有些对象需要向外部实体提出请求,以便代表它们执行某项操作,直到另行通知为止,这可能会对其他实体造成不利影响。例如,一个包含文件流的对象可能需要向文件系统(可以位于连接的宇宙中的任何地方)请求对文件的独占访问权。在许多情况下,对象对外部实体的需求将与外部代码对对象的需求相关联。例如,一旦客户端代码完成了与上述文件流对象相关的所有操作,该对象就不再需要对其关联的文件具有独占访问权(或者根本不需要访问该文件)。

一般来说,请求实体执行某项任务直到另行通知的对象X会产生交付此类通知的义务,但只要X的客户端可能需要X的服务,就无法交付此类通知。IDisposable的目的是提供一种统一的方式,让对象知道它们的服务将不再需要,以便它们可以通知代表它们行事的实体(如果有的话)它们的服务不再需要。调用IDisposable的代码既不需要知道也不需要关心对象从外部实体请求了什么(如果有的话)服务,因为IDisposable仅邀请对象履行对外部实体(如果有的话)的义务。
换言之,当对象请求外部实体代表其执行某项任务(通常是授予某个东西的独占使用权)直到另行通知时,它会获取资源,并在告知该外部实体其服务不再需要时释放资源。获取资源的代码并没有获得一个“东西”,而是承担了一项义务;释放资源并不是放弃一个“东西”,而是履行了一项义务。

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