Destructor和IDisposable之间的区别?
Destructor和IDisposable之间的区别?
我读过关于使用C#中的对象销毁/ IDisposable接口和析构函数,但对我来说,它们似乎做的是同一件事情?
这两者之间有什么区别?为什么要使用其中之一?事实上,在这个例子(下面的链接)中,这个代码同时使用IDisposable接口和析构函数:
http://msdn.microsoft.com/en-us/library/system.idisposable.aspx
注释说析构函数是当终止代码未使用时,但我该如何决定何时使用其中之一?
简短版本
如果你的对象的用户忘记调用IDisposable.Dispose
,那么finalizer会给你一个处理未托管资源的机会。
如果你的对象实现了IDisposable
,那么用户必须调用.Dispose
。你不必清理用户的残局,但这是一件好事。
我的在Stackoverflow上最受欢迎的回答从一开始告诉你为什么要使用IDisposable,它应该做什么,你的finalizer可以做什么,不应该做什么。
这个回答会让你震惊
人们用这句话来形容它:P
我写了一篇相当深入的文章,可以帮助解释什么是finalizers、IDisposable以及何时使用其中之一:http://gregbee.ch/blog/implementing-and-using-the-idisposable-interface
最相关的部分可能如下所述:
当您使用未托管资源(如句柄和数据库连接)时,您应确保使用最少的时间来保存这些资源,使用获取晚和释放早的原则。在C++中,释放资源通常在析构函数中完成,该函数在对象被删除时确定性地运行。然而,.NET运行时使用垃圾回收器(GC)清理和回收不再可达的对象使用的内存;由于这是周期性运行的,这意味着清理对象的时间是不确定的。这样的结果是,由于不存在确定性的运行时,因此托管对象不具有析构函数。
与析构函数不同,C#具有finalizers,这是通过重写基Object类上定义的Finalize方法实现的(尽管C#在此方面有一些令人困惑的地方,即使用C++析构函数语法~Object)。如果一个对象覆盖了Finalize方法,则该对象在超出范围时不会被GC收集,而是将其放置在finalizer队列中。在下一次GC周期中,队列中的所有finalizers运行(在当前实现中的单个线程上运行),并回收最终化对象的内存。从这个方面来看,为什么您不希望在finalizer中进行清理是相当明显的:它需要两个GC周期来收集对象,而只有一个线程在运行所有finalizer,而每个其他线程都被挂起,因此会影响性能。
所以,如果你没有析构函数,并且不想把清理留给最终器,则唯一的选择是手动、确定性地清理对象。输入IDisposable接口,它提供了支持此功能的标准,并定义了一个方法Dispose,在其中放置对象的清理逻辑。当在finally块中使用时,此接口提供与析构函数等效的功能。代码中finally块的原因主要是支持IDisposable接口;这就是为什么C++只使用try/except,因为析构函数不需要finally块的原因。