为什么Dispose()不管理托管资源和终结器?

时间:2015-07-29 14:29:35

标签: c# .net dispose idisposable disposable

我们都知道System.IDisposable模式。它已经描述了很多时间,也在StackOverflow:

link:Dispose() for cleaning up managed resources?

  

Disposable模式建议我只应处理托管资源,如果我的对象被处理,而不是在最终确定期间

您可以看到发生这种情况,因为建议使用以下代码:

protected void Dispose(bool disposing)
{
    if (disposing)
    {
        // Code to dispose the managed resources of the class
    }
    // Code to dispose the un-managed resources of the class
 }

我知道只要我的类有一个实现System.IDisposable的(私有)成员,我的类就应该实现System.IDisposable。如果布尔值为true,则Dispose(bool)应该调用私有成员的Dispose()。

如果在最终确定期间调用Dispose,为什么会出现问题?那么,如果在finalize期间调用它,为什么下面的Dispose会成为一个问题?

protected void Dispose(bool disposing)
{
    if (myDisposableObject != null)
    {
        myDisposableObject.Dispose();
        myDisposableObject = null;
    }
 }

2 个答案:

答案 0 :(得分:3)

一般来说,你应该尽快摆脱资源。如果你不需要资源,为什么要把它留在那里浪费内存?

此外,为了在完成期间调用Dispose(),您必须为对象创建一个终结器,即C#中的析构函数。但是,调用对象的终结器的确切时间是非确定性的,这意味着您的托管对象可能在那时不再安全/可访问。甚至执行终结器的线程也是非确定性的,这也可能导致难以预见的问题。

由于这些原因,应该创建终结器以仅释放非托管资源。

很少有程序员完全理解'最终确定如何运作。例如,垃圾收集器在对象实例化期间识别出您的类型具有终结器,并将您的实例放入名为finalizequeue的特殊内部数据结构中。实际上,当您使用sos.dll(windbg)调试应用程序时,您可以使用命令!finalizeQueue来显示具有终结器的对象,并且稍后将在最后确定。

答案 1 :(得分:3)

当一个对象的终结器运行时,对于它可能拥有的几乎任何IDisposable个对象,其中一个将成立:

  1. 它只保留了对其他对象的引用,并且其他对象的终结器已经运行,因此无需对其进行任何操作。

  2. 它只保留了对该另一个对象的引用,并且计划运行其他对象的终结器,即使它还没有,并且没有必要这样做任何事情。

  3. 其他对象仍在使用IDisposable对象,在这种情况下,终结器不得调用Dispose

  4. 另一个对象的Dispose方法无法从终结器线程上下文(或者更一般地说,除了创建对象的上下文之外的任何线程上下文)安全地运行,其中如果终结者不得拨打Dispose

  5. 即使在上述情况都不适用的情况下,知道的代码可能会知道很多关于它的清理要求,而不是它实现IDisposable,并且应该经常使用更详细的清理协议。