共用方式為


實作 Finalize 和 Dispose 以清除 Unmanaged 資源

Note注意事項

如需使用 C++ 的最終化與處置的詳細資訊,請參閱 Destructors and Finalizers in Visual C++

類別執行個體通常透過非執行階段所管理的資源,例如視窗控制代碼 (HWND)、資料庫連接等等,來封裝控制項。因此,您應該提供明確和隱含的方式來釋放這些資源。藉由在物件上實作受保護的 Finalize 方法來提供隱含控制 (C# 和 C++ 中為解構函式語法)。在不再有任何有效的物件參考之後,記憶體回收行程會某些時間點上呼叫這個方法。

在某些情況下,您可能想要提供程式設計人員在記憶體回收行程釋放物件之前,使用能夠明確釋放這些外部資源的物件。如果外部資源不足或太過消耗,若程式設計人員明確釋放不再被使用的資源,會達到更佳的效能。若要提供明確控制,請實作由 IDisposable 介面所提供的 Dispose 方法。物件的消費者應該在完成此物件的使用時呼叫此方法。即使此物件的其他參考仍然存在,還是可以呼叫 Dispose

請注意,即使當您使用 Dispose 來提供明確控制時,也應該使用 Finalize 方法提供隱含清除。如果程式設計人員呼叫 Dispose 失敗,則 Finalize 會提供備份,以避免資源被永久遺漏。

如需實作 FinalizeDispose 來清除 Unmanaged 資源的詳細資訊,請參閱記憶體回收。下列程式碼範例將說明用於實作 Dispose 的基本設計模式,這個範例需要 System 命名空間。

' Design pattern for a base class.

Public Class Base
   Implements IDisposable
    ' Field to handle multiple calls to Dispose gracefully.
    Dim disposed as Boolean = false
   
   ' Implement IDisposable.
   Public Overloads Sub Dispose() Implements IDisposable.Dispose
      Dispose(True)
      GC.SuppressFinalize(Me)
   End Sub

   Protected Overloads Overridable Sub Dispose(disposing As Boolean)
      If disposed = False Then
          If disposing Then
             ' Free other state (managed objects).
             disposed = True
          End If
      End If
      ' Free your own state (unmanaged objects).
      ' Set large fields to null.
   End Sub

   Protected Overrides Sub Finalize()
      ' Simply call Dispose(False).
      Dispose (False)
   End Sub
End Class

' Design pattern for a derived class.
Public Class Derived
   Inherits Base
   
    ' Field to handle multiple calls to Dispose gracefully.
    Dim disposed as Boolean = false
    
   Protected Overloads Overrides Sub Dispose(disposing As Boolean) 
      If disposed = False Then
          If disposing Then 
             ' Release managed resources.
             disposed = True
          End If
      End If
      ' Release unmanaged resources.
      ' Set large fields to null.
      ' Call Dispose on your base class.
      Mybase.Dispose(disposing)
   End Sub
   ' The derived class does not have a Finalize method
   ' or a Dispose method without parameters because it inherits
   ' them from the base class.
End Class
// Design pattern for a base class.
public class Base: IDisposable
{
   //Implement IDisposable.
   public void Dispose() 
   {
     Dispose(true);
      GC.SuppressFinalize(this); 
   }

   protected virtual void Dispose(bool disposing) 
   {
      if (disposing) 
      {
         // Free other state (managed objects).
      }
      // Free your own state (unmanaged objects).
      // Set large fields to null.
   }

   // Use C# destructor syntax for finalization code.
   ~Base()
   {
      // Simply call Dispose(false).
      Dispose (false);
   }
}
// Design pattern for a derived class.
public class Derived: Base
{   
   protected override void Dispose(bool disposing) 
   {
      if (disposing) 
      {
         // Release managed resources.
      }
      // Release unmanaged resources.
      // Set large fields to null.
      // Call Dispose on your base class.
      base.Dispose(disposing);
   }
   // The derived class does not have a Finalize method
   // or a Dispose method without parameters because it inherits
   // them from the base class.
}

如需可說明實作 FinalizeDispose 的設計模式之詳細程式碼範例,請參閱 實作 Dispose 方法

自訂 Dispose 方法名稱

有時候定義域特定的名稱要比 Dispose 更適合。例如,檔案封裝可能要使用方法名稱 Close。在這種情況下,會私用地實作 Dispose,以及建立可呼叫 Dispose 的公用 Close 方法。下列程式碼範例說明這個模式。您可以用適合於範圍的名稱取代 Close。這個範例需要 System 命名空間。

' Do not make this method overridable.
' A derived class should not be allowed
' to override this method.
Public Sub Close()
   ' Call the Dispose method with no parameters.
   Dispose()
End Sub
// Do not make this method virtual.
// A derived class should not be allowed
// to override this method.
public void Close()
{
   // Call the Dispose method with no parameters.
   Dispose();
}

Finalize

下列規則概述 Finalize 方法的用法方針:

  • 只在需要最終化的物件上實作 Finalize。有與 Finalize 方法關聯的效能成本。

  • 如果您需要 Finalize 方法,應考慮實作 IDisposable,讓類別的使用者得以避免發生叫用 Finalize 方法的成本。

  • 不要使 Finalize 方法更加顯露。它應該是 protected,而非 public

  • 物件的 Finalize 方法應該釋放其擁有的任何外部資源。此外,Finalize 方法應該只釋放物件所包含的資源。Finalize 方法不應該參考任何其他物件。

  • 除了物件的基底類別之外,不要直接在物件上呼叫 Finalize。這不是 C# 程式語言的有效作業。

  • 從物件的 Finalize 方法呼叫基底類別的 Finalize 方法。

    Note注意事項

    會使用 C# 和 C++ 解構函式語法來自動呼叫基底類別的 Finalize 方法。

處置

下列規則概述 Dispose 方法的使用方針:

  • 在型別上實作處置設計模式,該型別會封裝需要明確釋放的資源。使用者可以呼叫公用 Dispose 方法來釋放外部資源。

  • 在基底型別上實作處置設計模式,此型別一般都有包含資源的衍生型別,即使當基底型別並沒有時亦然。如果基底型別有 Close 方法,則通常表示需要實作 Dispose。在這種情況下,不要在基底型別上實作 Finalize 方法。Finalize 應該在任何引入需要清除的資源的衍生型別上被實作。

  • 釋放型別在其 Dispose 方法中所擁有的任何可處置資源。

  • 已經在執行個體上呼叫 Dispose 之後,藉由呼叫 GC.SuppressFinalize 方法來避免 Finalize 方法的執行。這個規則的例外情況是必須在不是 Dispose 所涵蓋的 Finalize 中完成工作的罕見狀況。

  • 如果基底類別會實作 IDisposable,則呼叫它的 Dispose 方法。

  • 不要假設 Dispose 將會被呼叫。型別所擁有的 Unmanaged 資源也應該在不呼叫 Dispose 的事件之 Finalize 方法中被釋放。

  • 當資源已被處置時,從這個型別的執行個體方法 (除了 Dispose 以外) 擲回 ObjectDisposedException 。這個規則不適用於 Dispose 方法,因為這個方法應該可以被呼叫多次而不擲回例外狀況。

  • 透過基底型別的階層架構將呼叫傳播到 DisposeDispose 方法應該釋放這個物件所包含的全部資源,以及這個物件所擁有的任何物件。例如,您可以建立類似 TextReader 的物件,其中包含 StreamEncoding,兩者都是由 TextReader 所建立,而不需要知道使用者。此外,StreamEncoding 都可以取得外部資源。當您在 TextReader 上呼叫 Dispose 方法時,它應該依次在 StreamEncoding 上呼叫 Dispose,使它們釋放其外部資源。

  • 您應該考慮在呼叫某物件的 Dispose 方法之後,不允許使用該物件。重新建立已經被處置的物件是一種很難實作的模式。

  • 允許呼叫 Dispose 方法多次,而不會擲回例外狀況。在第一次呼叫之後,方法應該不會做任何動作。

Portions Copyright 2005 Microsoft Corporation.All rights reserved.

Portions Copyright Addison-Wesley Corporation.All rights reserved.

如需設計方針的詳細資訊,請參閱由 Krzysztof Cwalina 和 Brad Abrams 所著,並由 Addison-Wesley 於 2005 年發行的「Framework 設計方針:可重複使用之 .NET 程式庫的慣例、慣用語法和模式」一書。

請參閱

參考

IDisposable.Dispose Method
Object.Finalize Method

其他資源

開發類別庫的設計方針
記憶體回收
設計模式