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

C# 关于C中Dispose()和析构函数的两个问题#,c#,.net,dispose,destructor,finalizer,C#,.net,Dispose,Destructor,Finalizer,我有一个关于如何使用Dispose()和析构函数的问题。阅读一些文章和MSDN,这似乎是实现Dispose()和析构函数的推荐方法 但我有两个关于此实现的问题,您可以在下面阅读: class Testing : IDisposable { bool _disposed = false; protected virtual void Dispose(bool disposing) { if (!_disposed) // only dispose once

我有一个关于如何使用
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);
    }
}
Dispose()上的GC.superssFinalize(this) 当程序员使用
using
或显式调用Dispose()时,我们的类正在调用
GC.supersfinalize(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?
    }
    
提前感谢

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

2.我们为什么不在此时处置[托管]资源?换句话说,为什么我们不能释放析构函数上的[托管]资源? 您可以,但这肯定是毫无意义的:您所在的对象已变得不可访问,因此所有拥有的托管资源也无法访问。它们将由GC在同一次运行中最终确定和收集,对它们调用Dispose()是不必要的,但并非完全没有风险或成本

2a在if内部必须执行哪些代码,在外部必须执行哪些代码?

if(disposing)
中,调用
\u myField.Dispose()

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

在外部,调用代码清理(close)非托管资源,如
Win32API.close(_myHandle)

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

这使得这个模式的完整(官方)实现只需要从继承测试的可能性来实现。
请注意,
Dispose(bool)
受到保护。当您声明类测试是密封的时,省略
~Testing()
是完全安全的

第一部分:

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

第二部分:


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

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

  • 它已经完成,在这种情况下,不需要清理
  • 它的终结器还没有运行,但计划运行,在这种情况下,不需要清理
  • 它只能在特定线程(不是终结器线程)内清理,在这种情况下,终结器线程不能尝试清理它
  • 它可能仍被其他人使用,在这种情况下,终结器线程不能尝试清理它

  • 在一些罕见的情况下,上面没有应用,在终结器中清理可能是合适的,但是除非首先检查了以上四种可能性,否则不应该考虑它。对于非托管资源,您通常应该使用

    SafeHandle
    ,而托管资源通常不需要终结器。@codein,您是对的,但是在MSDN上有什么规范性的评论吗?@CodeInChaos:请您提供一些关于它的文献,好吗?我个人同意一个学派的观点,即(非关键)终结器应该做的是通知程序员一个潜在的错误。我手头没有规范参考,但有几个博客描述了正常终结的问题(特别是它不总是执行,很难编码)或者safehandles/critical finalization的优点@Henk:编辑后大约2a:Than意味着即使程序员忘记调用dispose,非托管资源也会被清理掉?-1这是错误的。您不能在Finalizer中处理资源。引用可能无效,因此您不能触摸它们。@Guffa:引用不能变为无效只要您持有id,类型安全性就会一直保持到最终确定fase。这很棘手:myField可能已经被处置(但没有被收集!)。Dispose()在一个已处理的对象上应该是安全的。@Guffa:我认为Henk是正确的,因为他指的是
    disposing
    块中的dispose托管对象,而这不是终结器,是
    dispose()
    程序员发出的呼叫。Henk是对的,但是……值得再次强调的是,通过引用Finalizer中的托管
    IDisposable
    资源,您可以人为地使其生存更长时间。如果您没有在Finalizer中引用它,GC将可以免费收集它(如果有,请致电其后备定稿人。)