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

标签 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)。我的问题是:

  • 这到底是什么意思?是否会收集对象但不调用析构函数?我想答案是肯定的,因为 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?
    }
    

提前致谢

最佳答案

1。 SuppressFinalize 是做什么的?

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

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

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

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

if(disposing) 中,调用 _myField.Dispose()

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

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

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

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

关于c# - 关于C#中Dispose()和析构函数的两个问题,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/4615236/

相关文章:

c# - 如何在 C# 中处理托管和非托管对象?

c# - gtk-sharp 中的富文本?

c# - 如何从 Xamarin Forms 代码打开或访问 Android 片段中的数据?

C# 线程中止()

c# - 我们可以使用 List.Except 来确认一个列表是另一个列表的子集吗

c# - Dispose() 是将数据保存到光盘的好地方吗?

c# - DataGridView RichTextBox 行高问题

.net - linq 与 sql(或 .NET 应用程序与 SQL Server Management Studio)

.net - 使用.NET WinForm打印预览ZPL II命令,然后将其发送到Zebra打印机

c# - foreach over Hashtable 在第一个键上停止