关于C#中的Dispose()和析构函数的两个问题

时间:2011-01-06 13:12:46

标签: c# .net dispose destructor finalizer

我对如何使用Dispose()和析构函数有疑问。阅读一些文章和MSDN documentation,这似乎是实现Dispose()和析构函数的推荐方法。

但是我对这个实现有两个问题,你可以在下面阅读:

class Testing : IDisposable
{
    bool _disposed = false;

    protected virtual void Dispose(bool disposing)
    {
        if (!_disposed) // only dispose once!
        {
            if (disposing)
            {
                // Not in destructor, OK to reference other objects
            }
            // perform cleanup for this object
        }
        _disposed = true;
    }

    public void Dispose()
    {
        Dispose(true);

        // tell the GC not to finalize
        GC.SuppressFinalize(this);
    }

    ~Testing()
    {
        Dispose(false);
    }
}
在Dispose()上

GC.SupressFinalize(this)

当程序员使用using或调用Dispose()显式时,我们的类正在调用GC.SupressFinalize(this)。我的问题是:

  • 这究竟意味着什么?是否会收集对象但不调用析构函数?我想anwswer是肯定的,因为destructors被框架转换为Finalize()调用,但我不确定。

在没有Dispose()调用的情况下完成

假设GC要清理我们的对象,但程序员没有调用Dispose()

  • 为什么我们此时不处理资源?换句话说,为什么我们不能在析构函数上释放资源?
  • 必须在if里面执行什么代码,在外面执行什么?

    if (!_disposed) // only dispose once!
    {
       if (disposing)
       {
           //What should I do here and why?
       }
       // And what here and why?
    }
    

提前致谢

3 个答案:

答案 0 :(得分:13)

1。 SuppressFinalize做了什么?

它从终结器列表中取消注册对象,即当GC稍后收集对象时,它将忽略析构函数的存在。这是性能上的一大进步,因为析构函数否则需要对象的集合以及它所引用的所有内容的延迟。

2。为什么我们此时不处理[托管]资源?换句话说,为什么我们不能在析构函数上释放[managed]资源?

你可以,但肯定是没有意义的:你所在的对象已无法访问,因此所有拥有的托管资源也无法访问。它们将在同一次运行中由GC完成并收集,并且调用它们上的Dispose()是不必要的,但并非完全没有风险或成本。

2a必须在if里面执行什么代码,在外面执行什么?

if(disposing)内,请致电_myField.Dispose()

换句话说,处理托管资源(具有Dispose的对象)

在外面,调用代码来清理(关闭)非托管资源,例如Win32API.Close(_myHandle)

请注意,当您没有非托管资源时(通常是这样)(查找SafeHandle),您不需要析构函数,因此不需要SuppressFinalize。

这使得仅需要完整(官方)实现此模式,因为Test可能继承自。
请注意Dispose(bool)受到保护。当您将类测试声明为sealed时,它是完全安全的并且符合省略~Testing()

答案 1 :(得分:2)

第一部分:

当调用GC.SupressFinalize(this)时,GC会被告知该对象已经释放了其资源,并且可以将其作为任何其他对象进行垃圾收集。是的,终结和“析构函数”在.NET中是相同的。

第二部分:

最终确定由一个单独的线程完成,我们无法控制最终确定的时间和顺序,因此我们不知道是否有任何其他对象仍然可用或已经完成。因此,您无法引用disposing块之外的其他对象。

答案 2 :(得分:1)

绝大多数情况下,拥有IDisposable资源的对象最终确定后,以下至少一项陈述将适用于这些资源:

  1. 它已经完成,在这种情况下不需要清理。
  2. 它的终结器尚未运行,但计划这样做,在这种情况下不需要清理。
  3. 它只能在特定线程(不是终结器线程)中清理,在这种情况下,终结器线程不得尝试清理它。
  4. 它可能仍在被其他人使用,在这种情况下,终结器线程不得试图清理它。
  5. 在上述情况都不适用的一些罕见情况下,终结者内的清理可能是合适的,但除非人们首先检查上述四种可能性,否则不应该考虑清除。