IDisposable Schnittstelle

Definition

Stellt einen Mechanismus für die Freigabe nicht verwalteter Ressourcen bereit.

public interface class IDisposable
public interface IDisposable
[System.Runtime.InteropServices.ComVisible(true)]
public interface IDisposable
type IDisposable = interface
[<System.Runtime.InteropServices.ComVisible(true)>]
type IDisposable = interface
Public Interface IDisposable
Abgeleitet
Attribute

Beispiele

Im folgenden Beispiel wird veranschaulicht, wie eine Ressourcenklasse erstellt wird, die die -Schnittstelle IDisposable implementiert.

#using <System.dll>
#using <System.Windows.Forms.dll>

using namespace System;
using namespace System::ComponentModel;
using namespace System::Windows::Forms;

// The following example demonstrates how to create a class that 
// implements the IDisposable interface and the IDisposable.Dispose
// method with finalization to clean up unmanaged resources. 
//
public ref class MyResource: public IDisposable
{
private:

   // Pointer to an external unmanaged resource.
   IntPtr handle;

   // A managed resource this class uses.
   Component^ component;

   // Track whether Dispose has been called.
   bool disposed;

public:
   // The class constructor.
   MyResource( IntPtr handle, Component^ component )
   {
      this->handle = handle;
      this->component = component;
      disposed = false;
   }

   // This method is called if the user explicitly disposes of the
   // object (by calling the Dispose method in other managed languages, 
   // or the destructor in C++). The compiler emits as a call to 
   // GC::SuppressFinalize( this ) for you, so there is no need to 
   // call it here.
   ~MyResource() 
   {
      // Dispose of managed resources.
      component->~Component();

      // Call C++ finalizer to clean up unmanaged resources.
      this->!MyResource();

      // Mark the class as disposed. This flag allows you to throw an
      // exception if a disposed object is accessed.
      disposed = true;
   }

   // Use interop to call the method necessary to clean up the 
   // unmanaged resource.
   //
   [System::Runtime::InteropServices::DllImport("Kernel32")]
   static Boolean CloseHandle( IntPtr handle );

   // The C++ finalizer destructor ensures that unmanaged resources get
   // released if the user releases the object without explicitly 
   // disposing of it.
   //
   !MyResource()
   {      
      // Call the appropriate methods to clean up unmanaged 
      // resources here. If disposing is false when Dispose(bool,
      // disposing) is called, only the following code is executed.
      CloseHandle( handle );
      handle = IntPtr::Zero;
   }

};

void main()
{
   // Insert code here to create and use the MyResource object.
   MyResource^ mr = gcnew MyResource((IntPtr) 42, (Component^) gcnew Button());
   mr->~MyResource();
}
using System;
using System.ComponentModel;

// The following example demonstrates how to create
// a resource class that implements the IDisposable interface
// and the IDisposable.Dispose method.

public class DisposeExample
{
    // A base class that implements IDisposable.
    // By implementing IDisposable, you are announcing that
    // instances of this type allocate scarce resources.
    public class MyResource: IDisposable
    {
        // Pointer to an external unmanaged resource.
        private IntPtr handle;
        // Other managed resource this class uses.
        private Component component = new Component();
        // Track whether Dispose has been called.
        private bool disposed = false;

        // The class constructor.
        public MyResource(IntPtr handle)
        {
            this.handle = handle;
        }

        // Implement IDisposable.
        // Do not make this method virtual.
        // A derived class should not be able to override this method.
        public void Dispose()
        {
            Dispose(disposing: true);
            // This object will be cleaned up by the Dispose method.
            // Therefore, you should call GC.SuppressFinalize to
            // take this object off the finalization queue
            // and prevent finalization code for this object
            // from executing a second time.
            GC.SuppressFinalize(this);
        }

        // Dispose(bool disposing) executes in two distinct scenarios.
        // If disposing equals true, the method has been called directly
        // or indirectly by a user's code. Managed and unmanaged resources
        // can be disposed.
        // If disposing equals false, the method has been called by the
        // runtime from inside the finalizer and you should not reference
        // other objects. Only unmanaged resources can be disposed.
        protected virtual void Dispose(bool disposing)
        {
            // Check to see if Dispose has already been called.
            if(!this.disposed)
            {
                // If disposing equals true, dispose all managed
                // and unmanaged resources.
                if(disposing)
                {
                    // Dispose managed resources.
                    component.Dispose();
                }

                // Call the appropriate methods to clean up
                // unmanaged resources here.
                // If disposing is false,
                // only the following code is executed.
                CloseHandle(handle);
                handle = IntPtr.Zero;

                // Note disposing has been done.
                disposed = true;
            }
        }

        // Use interop to call the method necessary
        // to clean up the unmanaged resource.
        [System.Runtime.InteropServices.DllImport("Kernel32")]
        private extern static Boolean CloseHandle(IntPtr handle);

        // Use C# finalizer syntax for finalization code.
        // This finalizer will run only if the Dispose method
        // does not get called.
        // It gives your base class the opportunity to finalize.
        // Do not provide finalizer in types derived from this class.
        ~MyResource()
        {
            // Do not re-create Dispose clean-up code here.
            // Calling Dispose(disposing: false) is optimal in terms of
            // readability and maintainability.
            Dispose(disposing: false);
        }
    }
    public static void Main()
    {
        // Insert code here to create
        // and use the MyResource object.
    }
}
Imports System.ComponentModel

' The following example demonstrates how to create
' a resource class that implements the IDisposable interface
' and the IDisposable.Dispose method.
Public Class DisposeExample

   ' A class that implements IDisposable.
   ' By implementing IDisposable, you are announcing that
   ' instances of this type allocate scarce resources.
   Public Class MyResource
      Implements IDisposable
      ' Pointer to an external unmanaged resource.
      Private handle As IntPtr
      ' Other managed resource this class uses.
      Private component As component
      ' Track whether Dispose has been called.
      Private disposed As Boolean = False

      ' The class constructor.
      Public Sub New(ByVal handle As IntPtr)
         Me.handle = handle
      End Sub

      ' Implement IDisposable.
      ' Do not make this method virtual.
      ' A derived class should not be able to override this method.
      Public Overloads Sub Dispose() Implements IDisposable.Dispose
         Dispose(disposing:=True)
         ' This object will be cleaned up by the Dispose method.
         ' Therefore, you should call GC.SupressFinalize to
         ' take this object off the finalization queue
         ' and prevent finalization code for this object
         ' from executing a second time.
         GC.SuppressFinalize(Me)
      End Sub

      ' Dispose(bool disposing) executes in two distinct scenarios.
      ' If disposing equals true, the method has been called directly
      ' or indirectly by a user's code. Managed and unmanaged resources
      ' can be disposed.
      ' If disposing equals false, the method has been called by the
      ' runtime from inside the finalizer and you should not reference
      ' other objects. Only unmanaged resources can be disposed.
      Protected Overridable Overloads Sub Dispose(ByVal disposing As Boolean)
         ' Check to see if Dispose has already been called.
         If Not Me.disposed Then
            ' If disposing equals true, dispose all managed
            ' and unmanaged resources.
            If disposing Then
               ' Dispose managed resources.
               component.Dispose()
            End If

            ' Call the appropriate methods to clean up
            ' unmanaged resources here.
            ' If disposing is false,
            ' only the following code is executed.
            CloseHandle(handle)
            handle = IntPtr.Zero

            ' Note disposing has been done.
            disposed = True

         End If
      End Sub

      ' Use interop to call the method necessary
      ' to clean up the unmanaged resource.
      <System.Runtime.InteropServices.DllImport("Kernel32")> _
      Private Shared Function CloseHandle(ByVal handle As IntPtr) As [Boolean]
      End Function

      ' This finalizer will run only if the Dispose method
      ' does not get called.
      ' It gives your base class the opportunity to finalize.
      ' Do not provide finalize methods in types derived from this class.
      Protected Overrides Sub Finalize()
         ' Do not re-create Dispose clean-up code here.
         ' Calling Dispose(disposing:=False) is optimal in terms of
         ' readability and maintainability.
         Dispose(disposing:=False)
         MyBase.Finalize()
      End Sub
   End Class

   Public Shared Sub Main()
      ' Insert code here to create
      ' and use the MyResource object.
   End Sub

End Class

Hinweise

Diese Schnittstelle wird hauptsächlich verwendet, um nicht verwaltete Ressourcen frei zu geben. Der Garbage Collector gibt automatisch den Speicher frei, der einem verwalteten Objekt zugeordnet ist, wenn dieses Objekt nicht mehr verwendet wird. Es ist jedoch nicht möglich, vorherzusagen, wann die Garbage Collection erfolgt. Darüber hinaus hat der Garbage Collector keine Kenntnis von nicht verwalteten Ressourcen wie Fensterhandles oder geöffneten Dateien und Streams.

Verwenden Sie die -Methode dieser Schnittstelle, um nicht verwaltete Ressourcen in Verbindung mit dem Garbage Dispose Collector explizit frei zu geben. Der Consumer eines Objekts kann diese Methode aufrufen, wenn das Objekt nicht mehr benötigt wird.

Warnung

Es ist eine wichtige Änderung, die Schnittstelle IDisposable einer vorhandenen Klasse hinzuzufügen. Da bereits vorhandene Consumers Ihres Typs nicht aufrufen können, können Sie nicht sicher sein, dass nicht verwaltete Ressourcen, die von Ihrem Typ Dispose gehalten werden, freigegeben werden.

Da die Implementierung vom Consumer eines Typs aufgerufen wird, wenn die Ressourcen, die sich im Besitz einer Instanz befinden, nicht mehr benötigt werden, sollten Sie entweder das verwaltete Objekt in einem umschließen (die empfohlene Alternative), oder Sie sollten überschreiben, um nicht verwaltete Ressourcen frei zu geben, falls der Consumer vergessen hat, auf zu IDisposable.Dispose SafeHandle Object.Finalize Dispose rufen.

Wichtig

Im .NET Framework unterstützt der C++-Compiler die deterministische Beseitigung von Ressourcen und lässt keine direkte Implementierung der -Methode Dispose zu.

Eine ausführliche Erläuterung zur Verwendung dieser Schnittstelle und der -Methode finden Sie in den Themen Object.Finalize Garbage Collection und Implementing a Dispose Method (Implementieren einer Dispose-Methode).

Verwenden eines Objekts, das IDisposable implementiert

Wenn Ihre App einfach ein Objekt verwendet, das die -Schnittstelle implementiert, sollten Sie die -Implementierung des Objekts aufrufen, wenn IDisposable Sie mit der Verwendung fertig IDisposable.Dispose sind. Je nach Programmiersprache haben Sie zwei Möglichkeiten:

  • Mithilfe eines Sprachkonstrukts wie der using -Anweisung in C# und Visual Basic.

  • Durch Umschließen des Aufrufs der IDisposable.Dispose Implementierung in einen try / finally -Block.

Hinweis

Dokumentation für Typen, die IDisposable implementieren, beachten Sie diese Tatsache und enthalten eine Erinnerung zum Aufrufen der Dispose Implementierung.

C#- und Visual Basic Using-Anweisung

Wenn Ihre Sprache ein Konstrukt wie die using-Anweisung in C# und die Using-Anweisung in Visual Basic unterstützt, können Sie es verwenden, anstatt sich explizit selbst IDisposable.Dispose auf zu rufen. Im folgenden Beispiel wird dieser Ansatz verwendet, um eine Klasse zu definieren, die Informationen über eine Datei und die Anzahl der Wörter WordCount in dieser Datei beibwahrt.

using System;
using System.IO;
using System.Text.RegularExpressions;

public class WordCount
{
   private String filename = String.Empty;
   private int nWords = 0;
   private String pattern = @"\b\w+\b";

   public WordCount(string filename)
   {
      if (! File.Exists(filename))
         throw new FileNotFoundException("The file does not exist.");

      this.filename = filename;
      string txt = String.Empty;
      using (StreamReader sr = new StreamReader(filename)) {
         txt = sr.ReadToEnd();
      }
      nWords = Regex.Matches(txt, pattern).Count;
   }

   public string FullName
   { get { return filename; } }

   public string Name
   { get { return Path.GetFileName(filename); } }

   public int Count
   { get { return nWords; } }
}
Imports System.IO
Imports System.Text.RegularExpressions

Public Class WordCount
   Private filename As String
   Private nWords As Integer
   Private pattern As String = "\b\w+\b" 

   Public Sub New(filename As String)
      If Not File.Exists(filename) Then
         Throw New FileNotFoundException("The file does not exist.")
      End If   
      
      Me.filename = filename
      Dim txt As String = String.Empty
      Using sr As New StreamReader(filename)
         txt = sr.ReadToEnd()
      End Using
      nWords = Regex.Matches(txt, pattern).Count
   End Sub
   
   Public ReadOnly Property FullName As String
      Get
         Return filename
      End Get   
   End Property
   
   Public ReadOnly Property Name As String
      Get
         Return Path.GetFileName(filename)
      End Get   
   End Property
   
   Public ReadOnly Property Count As Integer
      Get
         Return nWords
      End Get
   End Property
End Class

Die using -Anweisung ist eigentlich ein syntaktischer Komfort. Zur Kompilierzeit implementiert der Sprachcompiler die Zwischensprache (Intermediate Language, IL) für einen try / finally -Block.

Weitere Informationen zur -Anweisung using finden Sie in den Themen Using-Anweisung oder Using-Anweisung.

Der Try/Finally-Block

Wenn Ihre Programmiersprache kein Konstrukt wie die -Anweisung in C# oder Visual Basic unterstützt oder sie nicht verwenden möchten, können Sie die Implementierung aus dem -Block einer -Anweisung using IDisposable.Dispose finally try / finally aufrufen. Im folgenden Beispiel wird der using -Block im vorherigen Beispiel durch einen -Block try / finally ersetzt.

using System;
using System.IO;
using System.Text.RegularExpressions;

public class WordCount
{
   private String filename = String.Empty;
   private int nWords = 0;
   private String pattern = @"\b\w+\b";

   public WordCount(string filename)
   {
      if (! File.Exists(filename))
         throw new FileNotFoundException("The file does not exist.");

      this.filename = filename;
      string txt = String.Empty;
      StreamReader sr = null;
      try {
         sr = new StreamReader(filename);
         txt = sr.ReadToEnd();
      }
      finally {
         if (sr != null) sr.Dispose();
      }
      nWords = Regex.Matches(txt, pattern).Count;
   }

   public string FullName
   { get { return filename; } }

   public string Name
   { get { return Path.GetFileName(filename); } }

   public int Count
   { get { return nWords; } }
}
Imports System.IO
Imports System.Text.RegularExpressions

Public Class WordCount
   Private filename As String
   Private nWords As Integer
   Private pattern As String = "\b\w+\b" 

   Public Sub New(filename As String)
      If Not File.Exists(filename) Then
         Throw New FileNotFoundException("The file does not exist.")
      End If   
      
      Me.filename = filename
      Dim txt As String = String.Empty
      Dim sr As StreamReader = Nothing
      Try
         sr = New StreamReader(filename)
         txt = sr.ReadToEnd()
      Finally
         If sr IsNot Nothing Then sr.Dispose() 
      End Try
      nWords = Regex.Matches(txt, pattern).Count
   End Sub
   
   Public ReadOnly Property FullName As String
      Get
         Return filename
      End Get   
   End Property
   
   Public ReadOnly Property Name As String
      Get
         Return Path.GetFileName(filename)
      End Get   
   End Property
   
   Public ReadOnly Property Count As Integer
      Get
         Return nWords
      End Get
   End Property
End Class

Weitere Informationen zum Muster try / finally finden Sie unter Try... Fangen... Finally-Anweisung, try-finallyoder try-finally-Anweisung.

Implementieren von IDisposable

Sie sollten implementieren, wenn Ihr Typ nicht verwaltete Ressourcen direkt verwendet oder sie IDisposable selbst verwerfbar verwenden möchten. Die Benutzer Ihres Typs können Ihre Implementierung aufrufen, um Ressourcen frei IDisposable.Dispose zu geben, wenn die Instanz nicht mehr benötigt wird. Um Fälle zu behandeln, in denen sie nicht aufrufen können, sollten Sie entweder eine von abgeleitete Klasse verwenden, um die nicht verwalteten Ressourcen zu umschließen, oder Sie sollten die -Methode für einen Verweistyp Dispose SafeHandle Object.Finalize überschreiben. In beiden Fällen verwenden Sie die -Methode, um alle erforderlichen Bereinigungen durchzuführen, nachdem Sie die nicht verwalteten Ressourcen verwendet haben, z. B. das Freigeben, Freigeben oder Zurücksetzen der nicht verwalteten Dispose Ressourcen. Weitere Informationen zum Implementieren von finden IDisposable.Dispose Sie unter der Dispose(bool)-Methodenüberladung.

Wichtig

Wenn Sie eine Basisklasse definieren, die nicht verwaltete Ressourcen verwendet und über Unterklassen verfügt, die verworfen werden sollen oder wahrscheinlich sind, sollten Sie die -Methode implementieren und eine zweite Überladung von bereitstellen, wie im nächsten Abschnitt IDisposable.Dispose Dispose erläutert.

IDisposable und die Vererbungshierarchie

Eine Basisklasse mit Unterklassen, die verwerfbar sein sollten, muss IDisposable wie folgt implementieren. Sie sollten dieses Muster immer dann verwenden, wenn Sie für einen beliebigen Typ implementieren, IDisposable der nicht ist ( in sealed NotInheritable Visual Basic).

  • Sie sollte eine öffentliche, nicht virtuelle Methode Dispose() und eine geschützte virtuelle Methode Dispose(Boolean disposing) bereitstellen.

  • Die Dispose() -Methode muss aufrufen Dispose(true) und sollte die Finalisierung zur Leistungssteigerung unterdrücken.

  • Der Basistyp sollte keine Finalizer enthalten.

Das folgende Codefragment spiegelt das Dispose-Muster für Basisklassen wider. Es wird davon ausgegangen, dass ihr Typ die -Methode nicht Object.Finalize überschreibt.

using Microsoft.Win32.SafeHandles;
using System;
using System.Runtime.InteropServices;

class BaseClass : IDisposable
{
   // Flag: Has Dispose already been called?
   bool disposed = false;
   // Instantiate a SafeHandle instance.
   SafeHandle handle = new SafeFileHandle(IntPtr.Zero, true);

   // Public implementation of Dispose pattern callable by consumers.
   public void Dispose()
   {
      Dispose(disposing: true);
      GC.SuppressFinalize(this);
   }

   // Protected implementation of Dispose pattern.
   protected virtual void Dispose(bool disposing)
   {
      if (disposed)
         return;

      if (disposing) {
         handle.Dispose();
         // Free any other managed objects here.
         //
      }

      disposed = true;
   }
}
Imports Microsoft.Win32.SafeHandles
Imports System.Runtime.InteropServices

Class BaseClass : Implements IDisposable
   ' Flag: Has Dispose already been called?
   Dim disposed As Boolean = False
   ' Instantiate a SafeHandle instance.
   Dim handle As SafeHandle = New SafeFileHandle(IntPtr.Zero, True)

   ' Public implementation of Dispose pattern callable by consumers.
   Public Sub Dispose() _
              Implements IDisposable.Dispose
      Dispose(disposing:=True)
      GC.SuppressFinalize(Me)
   End Sub

   ' Protected implementation of Dispose pattern.
   Protected Overridable Sub Dispose(disposing As Boolean)
      If disposed Then Return

      If disposing Then
         handle.Dispose()
         ' Free any other managed objects here.
         '
      End If

      disposed = True
   End Sub
End Class

Wenn Sie die -Methode Object.Finalize überschreiben, sollte Ihre -Klasse das folgende Muster implementieren.

using System;

class BaseClass : IDisposable
{
   // Flag: Has Dispose already been called?
   bool disposed = false;

   // Public implementation of Dispose pattern callable by consumers.
   public void Dispose()
   {
      Dispose(disposing: true);
      GC.SuppressFinalize(this);
   }

   // Protected implementation of Dispose pattern.
   protected virtual void Dispose(bool disposing)
   {
      if (disposed)
         return;

      if (disposing) {
         // Free any other managed objects here.
         //
      }

      // Free any unmanaged objects here.
      //
      disposed = true;
   }

   ~BaseClass()
   {
      Dispose(disposing: false);
   }
}
Class BaseClass : Implements IDisposable
   ' Flag: Has Dispose already been called?
   Dim disposed As Boolean = False

   ' Public implementation of Dispose pattern callable by consumers.
   Public Sub Dispose() _
              Implements IDisposable.Dispose
      Dispose(disposing:=True)
      GC.SuppressFinalize(Me)
   End Sub

   ' Protected implementation of Dispose pattern.
   Protected Overridable Sub Dispose(disposing As Boolean)
      If disposed Then Return

      If disposing Then
         ' Free any other managed objects here.
         '
      End If

      ' Free any unmanaged objects here.
      '
      disposed = True
   End Sub

   Protected Overrides Sub Finalize()
      Dispose(disposing:=False)
   End Sub
End Class

Unterklassen sollten das verwerfbare Muster wie folgt implementieren:

  • Sie müssen Dispose(Boolean) überschreiben und die Basisklassen-Dispose(Boolean)-Implementierung aufrufen.

  • Sie können bei Bedarf einen Finalizer bereitstellen. Der Finalizer muss Dispose(false) aufrufen.

Beachten Sie, dass abgeleitete Klassen selbst die -Schnittstelle nicht IDisposable implementieren und keine parameterlose Methode Dispose enthalten. Sie überschreiben nur die Dispose(Boolean) Basisklassenmethode.

Das folgende Codefragment spiegelt das Dispose-Muster für abgeleitete Klassen wider. Es wird davon ausgegangen, dass ihr Typ die -Methode nicht Object.Finalize überschreibt.

using Microsoft.Win32.SafeHandles;
using System;
using System.Runtime.InteropServices;

class DerivedClass : BaseClass
{
   // Flag: Has Dispose already been called?
   bool disposed = false;
   // Instantiate a SafeHandle instance.
   SafeHandle handle = new SafeFileHandle(IntPtr.Zero, true);

   // Protected implementation of Dispose pattern.
   protected override void Dispose(bool disposing)
   {
      if (disposed)
         return;

      if (disposing) {
         handle.Dispose();
         // Free any other managed objects here.
         //
      }

      // Free any unmanaged objects here.
      //

      disposed = true;
      // Call base class implementation.
      base.Dispose(disposing);
   }
}
Imports Microsoft.Win32.SafeHandles
Imports System.Runtime.InteropServices

Class DerivedClass : Inherits BaseClass
   ' Flag: Has Dispose already been called?
   Dim disposed As Boolean = False
   ' Instantiate a SafeHandle instance.
   Dim handle As SafeHandle = New SafeFileHandle(IntPtr.Zero, True)

   ' Protected implementation of Dispose pattern.
   Protected Overrides Sub Dispose(disposing As Boolean)
      If disposed Then Return

      If disposing Then
         handle.Dispose()
         ' Free any other managed objects here.
         '
      End If

      ' Free any unmanaged objects here.
      '
      disposed = True

      ' Call base class implementation.
      MyBase.Dispose(disposing)
   End Sub
End Class

Methoden

Dispose()

Führt anwendungsspezifische Aufgaben durch, die mit der Freigabe, der Zurückgabe oder dem Zurücksetzen von nicht verwalteten Ressourcen zusammenhängen.

Gilt für

Siehe auch