GarbageCollector取消成员字段?

时间:2011-09-20 22:32:02

标签: c# .net garbage-collection clr

我正在调试一些C#类(比方说,Foo),它实现了Dispose-Finalize模式,即如果尚未调用Dispose,它的Finalizer正在调用Dispose()。

在Dispose()中有一个日志代码可以访问Foo的某些成员(比方说Bar)。 Bar也是某个引用类型的实例,是readonly(在Foo的构造函数中创建),并且不会暴露在Foo之外的任何地方。因此,在Foo的垃圾收集时,Bar也可能已被收集。理论上说不应该从Finalize线程访问这样的成员字段。

但是日志记录代码并不了解理论,并试图记录一些Bar的属性。并且进程在Finalizer的线程中与NullReferenceException崩溃。

我理解当您忽略理论时可能会发生不好的事情,但我没有预料到NRE:垃圾收集器是否将对收集的对象的引用设为空?或者我错过了其他什么?

1 个答案:

答案 0 :(得分:2)

Implementing a Dispose Method中,他们特别提醒您要从终结器中访问其他对象。这就是他们有这种模式的原因:

~MyObject()
{
    Dispose(false);  // False because it's being called in a finalizer
}

public void Dispose()
{
    Dispose(true);  // True because it was called from user code
    GC.SuppressFinalize(this);
}

protected virtual void Dispose(bool disposing)
{
    if (disposing)
    {
        // here it's safe to access other CLR objects
    }

    // Here you dispose of any unmanaged objects
}

如果您偏离此模式 - 特别是如果终结器调用Dispose并尝试访问可能已经处理过的其他对象,那么您将遇到问题。

另请注意,除非您正在创建分配非托管资源的类,否则不需要终结器。如果您的类只使用提供.NET对象的CLR对象或第三方库,则不需要终结器。