我可以在终结器中安全地访问引用类型实例字段/属性吗?

Rob*_*Rob 9 .net c# dispose finalizer

我一直认为这个问题的答案是否定的,但我找不到任何来源说明这一点.在我下面的课程中,我可以访问C终结器中实例的(托管)字段/属性,即在ReleaseUnmanaged()?有什么限制,如果有的话?GC或者终结是否会将这些成员设置为空?

我唯一能找到的是终结队列中的东西可以按任意顺序完成.所以在这种情况下,由于建议类型应该允许用户Dispose()多次调用,为什么推荐的模式会打扰disposing boolean?如果我的终结者打电话Dispose(true)而不是Dispose(false)

public class C : IDisposable
{
    private void ReleaseUnmanaged() { }

    private void ReleaseOtherDisposables() { }

    protected virtual void Dispose(bool disposing)
    {
        ReleaseUnmanaged();
        if (disposing)
        {   
            ReleaseOtherDisposables();
        }
    }

    ~ C()
    {
        Dispose(false);
    }

    public void Dispose()
    {
        Dispose(true);
        GC.SuppressFinalize(this);
    }
}
Run Code Online (Sandbox Code Playgroud)

sup*_*cat 3

如果任何代码可以通过任何方式获取对对象的引用,GC 将永远不会收集任何对象。如果一个对象存在的唯一引用是弱引用,GC 将使它们无效,这样任何代码都无法获得对该对象的引用,从而能够收集它。

如果一个对象有一个活动的终结器,那么如果 GC收集它(但由于终结器的存在),GC 会将其添加到对象队列中,该对象的终结器应尽快运行,并且完成此操作后,将其删除。激活它。队列中的引用将阻止 GC 在终结器运行之前收集该对象;一旦终结器完成,如果该对象不存在其他引用并且尚未重新注册其终结器,则该对象将不再存在。

终结器访问外部对象的最大问题是:

  • 终结器将在与使用该对象的任何线程上下文无关的线程上下文中运行,但不应执行任何无法保证快速完成的操作。这通常会产生矛盾的要求,即代码在访问其他对象时使用锁定,但代码在等待锁时不会阻塞。

  • 如果终结器引用了另一个也有终结器的对象,则无法保证哪个对象将首先运行。

这两个因素都严重限制了具有终结器的对象安全访问它们不拥有的外部对象的能力。此外,由于终结器的实现方式,系统可能会在不存在强引用时决定运行终结器,但在终结器运行之前要创建和使用外部强引用;具有终结器的对象对于是否发生这种情况没有发言权。