2011-01-08 87 views
3

有沒有辦法來檢測一個對象是否調用了GC.SuppressFinalize?我可以檢測一個對象是否調用了GC.SuppressFinalize?

我有一個對象,它看起來像這樣(省略掉了清晰全面的Dispose模式):

public class ResourceWrapper { 
    private readonly bool _ownsResource; 
    private readonly UnmanagedResource _resource; 

    public ResourceWrapper(UnmanagedResource resource, bool ownsResource) { 
     _resource = resource; 
     _ownsResource = ownsResource; 
     if (!ownsResource) 
      GC.SuppressFinalize(this); 
    } 
    ~ResourceWrapper() { 
     if (_ownsResource) 
      // clean up the unmanaged resource 
    } 
} 

如果ownsResource構造函數的參數是false,那麼將終結無關 - 這樣這似乎是合理的(如果有點古怪)從構造函數中調用GC.SuppressFinalize。但是,因爲這種行爲很古怪,所以我很想在XML文檔註釋中記下它......如果我試圖對它進行評論,那麼我應該爲它寫一個單元測試。

不過,雖然System.GC有方法來設置對象的finalizability(SuppressFinalizeReRegisterForFinalize),我看不出有什麼方法來得到對象的finalizability。有沒有什麼方法可以查詢GC.SuppressFinalize是否在給定的實例上被調用,缺少購買Typemock或寫我自己的CLR主機?

回答

3

如果你想確認如果你的對象不擁有資源,最終確定已被抑制,也許你可以讓終結器聲明它擁有資源?測試必須執行GC.Collect和GC.WaitForPendingFinalizers,但生產代碼除了assert(可從生產版本中省略)之外不會有任何額外的內容。斷言的一個小警告:如果創建對象的線程在創建對象和設置所有權狀態之間死亡,則終結器可能不適當地運行。

上面已經說過,我想知道是否最好有一個抽象的ResourceWrapper類型,帶有單獨的子類型OwnedResourceWrapper和SharedResourceWrapper,它擁有或不擁有有問題的資源。然後,不擁有資源的子類型首先不需要有終結器。請注意,SharedResourceWrapper可能會將IDisposable作爲無操作來實現。

4

這是不可能的,GC只是不提供此信息。很好的理由,它不只是對象可以進入的兩個狀態。它也可能已經在最終確定隊列中,或者它可能已經完成。

自定義CLR主機不會幫助你,主機接口不提供任何掛鉤到gc。你可以檢查SuppressFinalize是否已經被調用,只要在終結器中檢查它就可以了。記錄(快速)。你不能證明相反。

Fwiw,.NET框架類不這樣做,他們只是讓終結器運行。

+0

一些BCL類實際上是從其構造函數中執行SuppressFinalize,例如, SqlConnection(儘管我沒有看到任何有條件的)。 – 2011-01-08 16:42:38

2

這可能有幫助(reductio absurdum)。一個竅門是在終結器中做一些日誌(這可能是一個靜態狀態),如果有人不在,他已經打電話給壓制最終確定,但你仍然無法確定何時。

這是工作,如果你是類型的作者。

+0

我想過那個。這也需要從我的測試中調用GC.Collect和GC.WaitForPendingFinalizers,儘管這是可行的。但我討厭讓生產代碼做額外的工作,僅用於測試。 – 2011-01-08 16:44:42

+0

我不推薦它,但仍然是一個解決方案。也許你會從別人那裏找到更可靠的解決方案。 – Xaqron 2011-01-08 16:46:29

相關問題