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

Dan*_*lba 16 .net c# dispose destructor finalizer

我有一个关于如何使用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);
    }
}
Run Code Online (Sandbox Code Playgroud)

Dispose()上的GC.SupressFinalize(this)

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

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

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

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

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

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

提前致谢

Hen*_*man 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().

  • @Guffa:只要你持有它,引用就不能变为无效.类型安全性一直持续到Finalize fase.这很棘手:myField可能已经被Disposed(但没有被收集!).Dispose()在Disposed对象上_should_是安全的. (2认同)