16

我有一个关于如何使用Dispose()和析构函数的问题。阅读一些文章和 MSDN文档,这似乎是推荐的实现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);
    }
}

GC.SupressFinalize(this) on Dispose()

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

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

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

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

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

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

提前致谢

4

3 回答 3

13

1. SuppressFinalize 是做什么的?

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

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

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

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

在里面if(disposing),调用 _myField.Dispose()

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

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

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

这使得只需要这个模式的完整(官方)实现,因为有可能继承 Test。
请注意,这Dispose(bool)是受保护的。当您声明您的类 Testing 为sealed时,省略~Testing().

于 2011-01-06T13:21:49.607 回答
2

第一部分:

GC.SupressFinalize(this)被调用时,GC 会被告知该对象已经释放了它的资源,并且它可以像任何其他对象一样被垃圾回收。是的,终结和“析构函数”在 .NET 中是一回事。

第二部分:

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

于 2011-01-06T13:23:05.537 回答
1

大多数情况下,当拥有IDisposable资源的对象最终确定时,至少以下语句之一将适用于这些资源中的每一个:

  1. 它已经完成,在这种情况下不需要清理。
  2. 它的终结器尚未运行,但计划这样做,在这种情况下不需要清理。
  3. 它只能在特定线程(不是终结器线程)内清理,在这种情况下终结器线程不能尝试清理它。
  4. 它可能仍在被其他人使用,在这种情况下,终结器线程不能尝试清理它。

在某些上述情况均不适用的极少数情况下,在终结器中进行清理可能是合适的,但除非首先检查了上述四种可能性,否则甚至不应该考虑它。

于 2015-11-19T00:16:12.973 回答