2011-09-20 55 views
1

我正在调试一些C#类(让我们说,Foo),它有一个Dispose-Finalize模式实现,即它的Finalizer调用Dispose(),如果Dispose尚未被调用。GarbageCollector无效成员字段?

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

但是日志代码没有意识到理论,并尝试记录酒吧的一些属性。并且该进程在Finalizer的线程中与NullReferenceException一起崩溃。

我明白,当你忽视理论时可能会发生不好的事情,但我并不期待NRE:垃圾收集器是否将收集到的对象的引用srt为空?还是我错过了别的?

+0

请参阅http://stackoverflow.com/questions/2327352/is-it-safe-to-access-a-reference-type-member-variable-in-a-finalizer –

+0

我不知道它是否实际上将其设置为null,但如果其内存已被回收,则无法访问该对象,因此必须执行某些操作或抛出一些错误。 –

回答

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和试图访问可能已经被置于其他对象,你将有问题。

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