2011-09-20 61 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對象的第三方庫,則不需要終結器。