2010-04-09 62 views
19

我有幾個問題,我無法得到正確的答案。我們爲什麼要在沒有析構函數時調用SuppressFinalize

1)爲什麼當我們沒有析構函數時,我們應該在Dispose函數中調用SuppressFinalize。

2)Dispose和finalize用於在垃圾收集對象之前釋放資源。無論是託管資源還是非託管資源,我們需要釋放資源,那麼爲什麼我們需要在dispose函數內部存在一個條件,當我們從IDisposable調用這個重寫函數時傳遞'true':Dispose並在從finalize調用時傳遞false。

看到下面的代碼,我從網上覆制。

class Test : IDisposable 
    { 
    private bool isDisposed = false; 

    ~Test() 
    { 
     Dispose(false); 
    } 

    protected void Dispose(bool disposing) 
    { 
     if (disposing) 
     { 
     // Code to dispose the managed resources of the class 
     } 
     // Code to dispose the un-managed resources of the class 

     isDisposed = true; 
    } 

    public void Dispose() 
    { 
     Dispose(true); 
     GC.SuppressFinalize(this); 
    } 
    } 

如果我刪除了布爾保護的Dispose函數並執行如下操作,該怎麼辦?

class Test : IDisposable 
    { 
    private bool isDisposed = false; 

    ~Test() 
    { 
     Dispose(); 
    } 


    public void Dispose() 
    { 
     // Code to dispose the managed resources of the class 
     // Code to dispose the un-managed resources of the class 
     isDisposed = true; 

     // Call this since we have a destructor . what if , if we don't have one 
     GC.SuppressFinalize(this); 
    } 
    }  

回答

17

我在這裏出門,但是...大多數人不需要需要全面的配置模式。它被設計成在直接訪問非託管資源(通常通過IntPtr)和麪對繼承時是堅實的。大多數時候,這些都不是必需的。

如果你只是持有一個實現IDisposable的其他東西的引用,那麼你幾乎肯定不需要終結器 - 無論是直接保存資源都負責處理這個事件。你可以做這樣的事情:

public sealed class Foo : IDisposable 
{ 
    private bool disposed; 
    private FileStream stream; 

    // Other code 

    public void Dispose() 
    { 
     if (disposed) 
     { 
      return; 
     } 
     stream.Dispose(); 
     disposed = true; 
    } 
} 

注意,這不是線程安全的,但是這可能不會是一個問題。由於不必擔心子類直接持有資源的可能性,因此不需要禁止終結器(因爲沒有一個) - 而且您不需要提供一種子類的方法來定製處置。沒有繼承,生活更簡單。

如果你需要允許不受控制的繼承(即你不願意打賭子類將有非常特殊的需求),那麼你需要去完整的模式。

請注意,與.NET 2.0中的SafeHandle相比,在.NET 1.1中需要自己的終結器更爲罕見。


爲了解決您爲什麼有一個在首位disposing標誌點:如果你是一個終結之內運行,你指的可能已經敲定的其他對象。你應該讓他們自己清理一下,你應該只清理你自己的資源,直接

+0

嗨,喬恩,只是挑剔,但句子「任何持有資源直接可以處理的」,應該可能是「將處理該」,(即「可以」 - >「將」),以強調根本不是外部班級的工作。 – 2010-04-09 10:21:13

+0

還有一個問題,因爲System.Object是所有對象的基礎,默認情況下它已經實現了一個finalize方法,即使我們沒有提供析構函數,也不會將GC放到finalize隊列中嗎?或者爲什麼我們說如果我們不提供destrutor對象不會被放入最終隊列?因爲通過繼承保護成員就像派生類的私有成員。 – somaraj 2010-04-09 10:58:46

+0

從非平凡的父類派生的子類是否有任何合法的原因,如果父類不具有清理終結器?我想不出任何情況下,派生類將任何非託管資源封裝到自己的類中,並將其自己的終結器完全脫離主類。實際上,即使所有人都想要一個「警鐘」終結器,最好將* *封裝到它自己的類中,而不是爲派生類添加終結器。 – supercat 2012-04-12 15:01:37

5

保留第一個版本,它更安全,並且是正確的dispose模式實現。

  1. 調用SuppressFinalize告訴你已完成所有銷燬/處置自己(通過你的類持有的資源),它不需要調用析構函數的GC。

  2. 你需要測試的情況下,使用您的類的代碼有已經調用了處置,你不應該告訴GC重新配置。

請參閱this MSDN文檔(Dispose方法應該調用SuppressFinalize)。

+0

是我不明白的是SupressFinalze將阻止GC調用敲定。但是我的疑問是,當我沒有一個決定者時,爲什麼我們需要打電話給SupressFinalze。因爲Finalize會在終結者隊列中調用那些objets,並且我的對象沒有析構函數,所以GC不會調用。 2)我的第二個特點是,爲什麼處理模式堅持要使用布爾值的重載處理函數。這將控制託管或非託管資源的發佈。 當對象要處理時,爲什麼我們需要分別處理資源,讓所有的空閒。 – somaraj 2010-04-09 06:36:06

+2

該規則僅在您需要終結器或您需要允許子類具有終結器時才相關。在很多情況下情況並非如此。 – 2010-04-09 06:36:31

+5

@somaraj:問題在於*你的類可能沒有終結器,而是一個*子類*。 – 2010-04-09 06:37:09

3

以下是主要事實

1)Object.Finalize是當它有什麼類重寫終結。 2)如果你在處理Finalization之前在你的Dispose方法中處理資源(例如,當從一個using塊中出來時),你可以調用GC.SuppressFinalize等等)。如果你沒有Finalizer,那麼你不需要這樣做。如果你有一個Finalizer,這可以確保該對象從Finalization隊列中取出(所以我們不會處理東西兩次,因爲Finalizer通常也會調用Dispose方法)

3)您將Finalizer實現爲'失敗安全「機制。終結器保證運行(只要CLR沒有中止),所以它們允許你確保代碼在Dispose方法未被調用的情況下得到清理(可能程序員忘記在'using'中創建實例,塊等

4)終結器是昂貴的,因爲類型的終結器無法在第0代收集(最有效)垃圾收集,並提升到第1代與參考他們的F可達性隊列,以便它們代表GC根。直到GC執行一個第一代集合,終結器被調用,並且資源被釋放 - 所以只有在非常重要的時候才實現終結器 - 並且確保需要最終化的對象儘可能小 - 因爲所有可以通過您的可終結對象將達到將被提升到第一代也。

2

1回答第一個問題

基本上,你不必調用SuppressFinalize方法,如果你的類沒有一個finalize方法(析構函數)。我相信人們稱之爲SupressFinalize,即使因缺乏知識而沒有最終確定方法。

2回答第二個問題的定案方法的

目的是釋放非託管資源。要理解的最重要的事情是,當對象處於最終化隊列中時,會調用Finalize方法。垃圾收集器收集所有可能被破壞的物體。垃圾收集器在銷燬之前將已完成定稿的對象添加到定型隊列中。還有另外一個.net後臺進程爲那些在最終化隊列中的對象調用finalize方法。到後臺進程執行finalize方法時,該特定對象的其他託管引用可能已被銷燬。因爲在最終執行時沒有特定的順序。因此,Dispose模式希望確保finalize方法不會嘗試訪問託管對象。這就是爲什麼託管對象在「final(處置)」子句中無法訪問finalize方法的原因。

1

您應該始終調用SuppressFinalize(),因爲您可能有(或將來有)實現Finalizer的派生類 - 在這種情況下,您需要它。

假設您有一個沒有Finalizer的基類 - 並且您決定不調用SuppressFinalize()。然後在3個月後添加一個派生類,添加一個Finalizer。很可能您會忘記進入基類並添加對SuppressFinalize()的調用。如果沒有終結器,調用它也沒有什麼壞處。

我建議IDisposable模式被張貼在這裏:How to properly implement the Dispose Pattern

相關問題