Freigeben über


Implementieren der Methoden "Finalize" und "Dispose" zum Bereinigen von nicht verwalteten Ressourcen

Aktualisiert: November 2007

Tipp

Informationen zum Abschließen und Bereinigen unter Verwendung von C++ finden Sie unter Destructors and Finalizers in Visual C++.

Klasseninstanzen kapseln häufig die Steuerung von Ressourcen, die nicht durch die Runtime verwaltet werden, z. B. Fensterhandles (HWND), Datenbankverbindungen usw. Daher sollten Sie sowohl eine explizite als auch eine implizite Methode für die Freigabe dieser Ressourcen bereitstellen. Stellen Sie eine implizite Steuerung bereit, indem Sie die geschützte Finalize für ein Objekt implementieren (Destruktorsyntax in C# und C++). Die Garbage Collection ruft diese Methode am gleichen Punkt auf, wenn keine gültigen Verweise auf das Objekt mehr vorhanden sind.

In manchen Fällen empfiehlt es sich, den Programmierern bei der Verwendung eines Objekts die Möglichkeit zu geben, diese externen Ressourcen explizit freizugeben, bevor die Garbage Collection das Objekt freigibt. Wenn eine externe Ressource knapp ist oder die Leistung beeinträchtigt, kann eine Leistungssteigerung erzielt werden, wenn der Programmierer Ressourcen explizit freigibt, sobald sie nicht mehr verwendet werden. Um explizite Steuerung bereitzustellen, implementieren Sie die Dispose, die von IDisposable bereitgestellt wird. Der Consumer des Objekts sollte diese Methode aufrufen, wenn sie das Objekt nicht mehr verwendet. Dispose kann auch dann aufgerufen werden, wenn andere Verweise auf das Objekt aktiv sind.

Beachten Sie, dass Sie auch bei Bereitstellung einer expliziten Steuerung mithilfe von Dispose eine implizite Bereinigung mithilfe der Finalize-Methode bereitstellen müssen. Finalize bietet eine Sicherung, um permanente Ressourcenverluste zu verhindern, falls der Programmierer Dispose nicht aufruft.

Weitere Informationen über das Implementieren von Finalize und Dispose zum Bereinigen nicht verwalteter Ressourcen finden Sie unter Garbage Collection. Das folgende Codebeispiel veranschaulicht das grundlegende Entwurfsschema für die Implementierung von Dispose. Für dieses Beispiel ist der System-Namespace erforderlich.

' 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.
}

Ein ausführlicheres Codebeispiel, in dem das Entwurfsschema für die Implementierung von Finalize und Dispose veranschaulicht wird, finden Sie unter Implementieren einer Dispose-Methode.

Anpassen des Namens einer Dispose-Methode

In bestimmten Fällen ist ein domänenspezifischer Name dem Namen Dispose vorzuziehen. So kann z. B. für eine Dateikapselung der Methodenname Close erforderlich sein. Implementieren Sie in diesem Fall Dispose privat, und erstellen Sie eine öffentliche Close-Methode, die Dispose aufruft. Das folgende Codebeispiel veranschaulicht dieses Schema. Sie können Close durch einen für Ihre Domäne geeigneten Methodennamen ersetzen. Für dieses Beispiel ist der System-Namespace erforderlich.

' 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

Die folgenden Regeln dienen als Richtlinie für die Verwendung der Finalize-Methode:

  • Implementieren Sie Finalize nur für Objekte, die einen Abschluss erfordern. Finalize-Methoden wirken sich auf die Leistung aus.

  • Wenn eine Finalize-Methode erforderlich ist, empfiehlt sich möglicherweise die Implementierung von IDisposable, damit die Benutzer der Klasse nicht erst die Finalize-Methode aufrufen müssen.

  • Erhöhen Sie nicht die Sichtbarkeit der Finalize-Methode. Die Methode sollte protected sein, nicht public.

  • Die Finalize-Methode eines Objekts sollte alle externen Ressourcen freigeben, derern Eigentümer das Objekt ist. Außerdem sollte eine Finalize-Methode nur die Ressourcen freigeben, die von dem Objekt verwendet werden. Die Finalize-Methode sollte nicht auf andere Objekte verweisen.

  • Rufen Sie eine Finalize-Methode nicht direkt für ein anderes Objekt als für die Basisklasse des Objekts auf. In der Programmiersprache C# ist dies eine ungültige Operation.

  • Rufen Sie die Finalize-Methode der Basisklasse in der Finalize-Methode eines Objekts auf.

    Tipp

    Mit der C#- und C++-Destruktorsyntax wird die Finalize-Methode der Basisklasse automatisch aufgerufen.

Dispose

Die folgenden Regeln bieten Richtlinien für die Verwendung der Dispose-Methode:

  • Implementieren Sie das Dispose-Entwurfsmuster für einen Typ, der Ressourcen kapselt, die explizit freigegeben werden müssen. Die Benutzer können externe Ressourcen freigeben, indem sie die öffentliche Dispose-Methode aufrufen.

  • Implementieren Sie das Dispose-Entwurfsmuster für einen Basistyp, der normalerweise abgeleitete Typen aufweist, die Ressourcen verwenden, auch wenn der Basistyp keine Ressourcen verwendet. Wenn der Basistyp über eine Close-Methode verfügt, weist dies häufig darauf hin, dass eine Dispose-Methode implementiert werden muss. Implementieren Sie in solchen Fällen keine Finalize-Methode für den Basistyp. Finalize sollte für abgeleitete Typen implementiert werden, die Ressourcen einfügen, die eine Bereinigung erforderlich machen.

  • Geben Sie alle freigebbaren Ressourcen, deren Eigentümer ein Typ ist, in der zugehörigen Dispose-Methode frei.

  • Unterbinden Sie nach dem Aufruf von Dispose für eine Instanz die Ausführung der Finalize-Methode, indem Sie die GC.SuppressFinalize aufrufen. Eine Ausnahme zu dieser Regel ist der seltene Fall, dass Finalize Operationen ausführen muss, die durch Dispose nicht abgedeckt sind.

  • Rufen Sie die Dispose-Methode der Basisklasse auf, wenn sie IDisposable implementiert.

  • Gehen Sie nicht davon aus, dass Dispose aufgerufen wird. Nicht verwaltete Ressourcen, deren Eigentümer ein Typ ist, sollten ebenfalls in einer Finalize-Methode freigegeben werden, falls Dispose nicht aufgerufen wird.

  • Lösen Sie für diesen Typ eine ObjectDisposedException über Instanzmethoden (nicht Dispose) aus, wenn die Ressourcen bereits freigegeben wurden. Diese Regel gilt nicht für die Dispose-Methode, da diese mehrfach aufrufbar sein sollte, ohne eine Ausnahme auszulösen.

  • Geben Sie die Aufrufe von Dispose über die Hierarchie der Basistypen weiter. Die Dispose-Methode sollte alle Ressourcen freigeben, die von diesem Objekt verwendet werden, und alle Objekte, deren Eigentümer dieses Objekt ist. Sie können z. B. ein TextReader-Objekt erstellen, das einen Stream und ein Encoding verwendet, die beide ohne Wissen des Benutzers durch den TextReader erstellt werden. Darüber hinaus können sowohl Stream als auch Encoding externe Ressourcen abrufen. Wenn Sie die Dispose-Methode für den TextReader aufrufen, sollte sie wiederum die Dispose-Methode für Stream und Encoding aufrufen, sodass diese ihre externen Ressourcen freigeben.

  • Es empfiehlt sich u. U. festzulegen, dass ein Objekt nicht mehr verwendet werden kann, nachdem seine Dispose-Methode aufgerufen wurde. Die Neuerstellung eines Objekts, das bereits freigegeben wurde, ist ein schwieriges Implementierungsproblem.

  • Lassen Sie zu, dass eine Dispose-Methode mehrmals aufgerufen werden kann, ohne dass eine Ausnahme ausgelöst wird. Nach dem ersten Aufruf sollte die Methode keine Operation ausführen.

Copyright für einzelne Teile 2005 Microsoft Corporation. Alle Rechte vorbehalten.

Copyright für einzelne Teile Addison-Wesley Corporation. Alle Rechte vorbehalten.

Weitere Informationen zu Entwurfsrichtlinien finden Sie im Buch "Framework Design Guidelines: Conventions, Idioms, and Patterns for Reusable .NET Libraries" von Krzysztof Cwalina und Brad Abrams, veröffentlicht von Addison-Wesley, 2005.

Siehe auch

Referenz

IDisposable.Dispose

Object.Finalize

Weitere Ressourcen

Entwurfsrichtlinien zum Entwickeln von Klassenbibliotheken

Garbage Collection

Entwurfsmuster