Implementieren einer Dispose-MethodeImplementing a Dispose method

Sie implementieren eine Dispose-Methode, um nicht verwaltete Ressourcen freizugeben, die von Ihrer Anwendung verwendet werden.You implement a Dispose method to release unmanaged resources used by your application. Der .NET-Garbage Collector ordnet nicht verwalteten Arbeitsspeicher weder zu noch gibt er diesen frei.The .NET garbage collector does not allocate or release unmanaged memory.

Das Muster für das Verwerfen eines Objekts, Dispose-Muster genannt, legt die Ordnung für die Lebensdauer eines Objekts fest.The pattern for disposing an object, referred to as a dispose pattern, imposes order on the lifetime of an object. Das Dispose-Muster wird nur für Objekte verwendet, die auf nicht verwaltete Ressourcen zugreifen, wie etwa Datei- und Pipehandles, Registrierungshandles, Wait-Handles oder Zeiger auf Blöcke nicht verwalteten Speichers.The dispose pattern is used only for objects that access unmanaged resources, such as file and pipe handles, registry handles, wait handles, or pointers to blocks of unmanaged memory. Dies liegt daran, dass der Garbage Collector beim Freigeben nicht verwendeter verwalteter Objekte sehr effizient ist, nicht verwaltete Objekt jedoch nicht freigeben kann.This is because the garbage collector is very efficient at reclaiming unused managed objects, but it is unable to reclaim unmanaged objects.

Das Dispose-Muster weist zwei Varianten auf:The dispose pattern has two variations:

  • Sie umschließen jede nicht verwaltete Ressource, die ein Typ verwendet, in einem SafeHandle (also in einer von System.Runtime.InteropServices.SafeHandle abgeleiteten Klasse).You wrap each unmanaged resource that a type uses in a safe handle (that is, in a class derived from System.Runtime.InteropServices.SafeHandle). In diesem Fall implementieren Sie die IDisposable-Schnittstelle und eine zusätzliche Dispose(Boolean)-Methode.In this case, you implement the IDisposable interface and an additional Dispose(Boolean) method. Dies ist die empfohlene Variante und erfordert nicht das Überschreiben der Object.Finalize-Methode.This is the recommended variation and doesn't require overriding the Object.Finalize method.

    Hinweis

    Der Microsoft.Win32.SafeHandles-Namespace stellt einen Satz von Klassen bereit, die von SafeHandle abgeleitet werden und im Abschnitt Verwenden von SafeHandles aufgeführt sind.The Microsoft.Win32.SafeHandles namespace provides a set of classes derived from SafeHandle, which are listed in the Using safe handles section. Wenn Sie keine Klasse finden können, die Ihre nicht verwaltete Ressource freigeben kann, können Sie eine eigene Unterklasse von SafeHandle implementieren.If you can't find a class that is suitable for releasing your unmanaged resource, you can implement your own subclass of SafeHandle.

  • Sie implementieren die IDisposable-Schnittstelle und eine zusätzliche Dispose(Boolean)-Methode, und Sie überschreiben auch die Object.Finalize-Methode.You implement the IDisposable interface and an additional Dispose(Boolean) method, and you also override the Object.Finalize method. Sie müssen Finalize überschreiben, um sicherzustellen, dass nicht verwaltete Ressourcen verworfen werden, wenn die IDisposable.Dispose-Implementierung nicht von einem Consumer Ihres Typs aufgerufen wird.You must override Finalize to ensure that unmanaged resources are disposed of if your IDisposable.Dispose implementation is not called by a consumer of your type. Wenn Sie das unter dem vorherigen Aufzählungspunkt beschriebene empfohlene Verfahren anwenden, führt die System.Runtime.InteropServices.SafeHandle-Klasse dies für Sie durch.If you use the recommended technique discussed in the previous bullet, the System.Runtime.InteropServices.SafeHandle class does this on your behalf.

Um sicherzustellen, dass Ressourcen immer entsprechend bereinigt werden, sollte eine Dispose-Methode auch mehrmals aufgerufen werden können, ohne eine Ausnahme auszulösen.To help ensure that resources are always cleaned up appropriately, a Dispose method should be callable multiple times without throwing an exception.

Das Codebeispiel für die GC.KeepAlive-Methode veranschaulicht, wie durch agressive Garbage Collection die Ausführung eines Finalizers bewirkt werden kann, während ein Member des freigegebenen Objekts noch ausgeführt wird.The code example provided for the GC.KeepAlive method shows how aggressive garbage collection can cause a finalizer to run while a member of the reclaimed object is still executing. Es empfiehlt sich, die KeepAlive-Methode am Ende einer längeren Dispose-Methode aufzurufen.It is a good idea to call the KeepAlive method at the end of a lengthy Dispose method.

Dispose() und Dispose(Boolean)Dispose() and Dispose(Boolean)

Die IDisposable-Schnittstelle erfordert die Implementierung einer einzelnen parameterlosen Methode, Dispose.The IDisposable interface requires the implementation of a single parameterless method, Dispose. Für das Dispose-Muster müssen jedoch zwei Dispose-Methoden implementiert werden:However, the dispose pattern requires two Dispose methods to be implemented:

  • Eine öffentliche, nicht virtuelle (NonInheritable in Visual Basic) IDisposable.Dispose-Implementierung, die keine Parameter aufweist.A public non-virtual (NonInheritable in Visual Basic) IDisposable.Dispose implementation that has no parameters.

  • Eine geschützte, virtuelle (Overridable in Visual Basic) Dispose-Methode mit der folgenden Signatur:A protected virtual (Overridable in Visual Basic) Dispose method whose signature is:

    protected virtual void Dispose(bool disposing)
    
    Protected Overridable Sub Dispose(disposing As Boolean)
    

Die Dispose() ÜberladungThe Dispose() overload

Da die öffentliche, nicht virtuelle (NonInheritable in Visual Basic), parameterlose Dispose-Methode von einem Consumer des Typs aufgerufen wird, besteht ihr Zweck darin, nicht verwaltete Ressourcen freizugeben und anzugeben, dass der Finalizer, sofern vorhanden, nicht ausgeführt werden muss.Because the public, non-virtual (NonInheritable in Visual Basic), parameterless Dispose method is called by a consumer of the type, its purpose is to free unmanaged resources and to indicate that the finalizer, if one is present, doesn't have to run. Daher weist sie eine Standardimplementierung auf:Because of this, it has a standard implementation:

public void Dispose()
{
   // Dispose of unmanaged resources.
   Dispose(true);
   // Suppress finalization.
   GC.SuppressFinalize(this);
}
Public Sub Dispose() _
           Implements IDisposable.Dispose
   ' Dispose of unmanaged resources.
   Dispose(True)
   ' Suppress finalization.
   GC.SuppressFinalize(Me)
End Sub

Die Dispose-Methode führt die Bereinigung aller Objekte aus, damit der Garbage Collector nicht mehr die Object.Finalize-Überschreibung der Objekte aufrufen muss.The Dispose method performs all object cleanup, so the garbage collector no longer needs to call the objects' Object.Finalize override. Daher verhindert der Aufruf der SuppressFinalize-Methode, dass der Garbage Collector den Finalizer ausführt.Therefore, the call to the SuppressFinalize method prevents the garbage collector from running the finalizer. Wenn der Typ keinen Finalizer aufweist, bleibt der Aufruf von GC.SuppressFinalize ohne Auswirkungen.If the type has no finalizer, the call to GC.SuppressFinalize has no effect. Beachten Sie, dass die tatsächliche Arbeit des Freigebens nicht verwalteter Ressourcen durch die zweite Überladung der Dispose-Methode ausgeführt wird.Note that the actual work of releasing unmanaged resources is performed by the second overload of the Dispose method.

Die Dispose(Boolean) ÜberladungThe Dispose(Boolean) overload

In der zweiten Überladung ist der disposing-Parameter ein Boolean, der angibt, ob der Methodenaufruf von einer Dispose-Methode (der Wert ist true) oder von einem Finalizer (der Wert ist false) stammt.In the second overload, the disposing parameter is a Boolean that indicates whether the method call comes from a Dispose method (its value is true) or from a finalizer (its value is false).

Der Text der Methode besteht aus zwei Codeblöcken:The body of the method consists of two blocks of code:

  • Ein Block, der nicht verwaltete Ressourcen freigibt.A block that frees unmanaged resources. Dieser Block wird unabhängig vom Wert des disposing-Parameters ausgeführt.This block executes regardless of the value of the disposing parameter.

  • Ein bedingter Block, der verwaltete Ressourcen freigibt.A conditional block that frees managed resources. Dieser Block wird ausgeführt, wenn der Wert von disposing gleich true ist.This block executes if the value of disposing is true. Die verwalteten Ressourcen, die freigegeben werden, können Folgendes umfassen:The managed resources that it frees can include:

    Verwaltete Objekte, die IDisposable implementieren.Managed objects that implement IDisposable. Der bedingte Block kann verwendet werden, um deren Dispose-Implementierung aufzurufen.The conditional block can be used to call their Dispose implementation. Wenn Sie ein SafeHandle verwendet haben, um die nicht verwaltete Ressource einschließen, sollten Sie die SafeHandle.Dispose(Boolean)-Implementierung hier aufrufen.If you have used a safe handle to wrap your unmanaged resource, you should call the SafeHandle.Dispose(Boolean) implementation here.

    Verwaltete Objekte, die viel Arbeitsspeicher belegen oder knappe Ressourcen nutzen.Managed objects that consume large amounts of memory or consume scarce resources. Durch die explizite Freigabe in der Dispose-Methode werden diese Objekte schneller freigegeben, als wenn sie vom Garbage Collector nicht deterministisch freigegeben werden würden.Freeing these objects explicitly in the Dispose method releases them faster than if they were reclaimed non-deterministically by the garbage collector.

Wenn der Methodenaufruf von einem Finalizer stammt (das heißt, disposing ist false), wird nur der Code ausgeführt, der nicht verwaltete Ressourcen freigibt.If the method call comes from a finalizer (that is, if disposing is false), only the code that frees unmanaged resources executes. Die Reihenfolge, in der der Garbage Collector verwaltete Objekte während des Abschlusses zerstört, ist nicht definiert. Durch Aufrufen dieser Dispose-Überladung mit dem Wert false wird daher verhindert, dass der Finalizer versucht, verwaltete Ressourcen freizugeben, die möglicherweise bereits freigegeben wurden.Because the order in which the garbage collector destroys managed objects during finalization is not defined, calling this Dispose overload with a value of false prevents the finalizer from trying to release managed resources that may have already been reclaimed.

Implementieren des Dispose-Musters für eine BasisklasseImplementing the dispose pattern for a base class

Wenn Sie das Dispose-Muster für eine Basisklasse implementieren, müssen Sie Folgendes bereitstellen:If you implement the dispose pattern for a base class, you must provide the following:

Wichtig

Sie sollten dieses Muster für alle Basisklassen implementieren, die Dispose() implementieren und nicht sealed (NotInheritable in Visual Basic) sind.You should implement this pattern for all base classes that implement Dispose() and are not sealed (NotInheritable in Visual Basic).

  • Eine Dispose-Implementierung, die die Dispose(Boolean)-Methode aufruft.A Dispose implementation that calls the Dispose(Boolean) method.

  • Eine Dispose(Boolean)-Methode, die die eigentliche Arbeit des Freigebens von Ressourcen ausführt.A Dispose(Boolean) method that performs the actual work of releasing resources.

  • Entweder eine von SafeHandle abgeleitete Klasse, die die nicht verwaltete Ressource einschließt (empfohlen) oder eine Überschreibung der Object.Finalize-Methode.Either a class derived from SafeHandle that wraps your unmanaged resource (recommended), or an override to the Object.Finalize method. Die SafeHandle-Klasse stellt einen Finalizer bereit, wodurch Sie keinen programmieren müssen.The SafeHandle class provides a finalizer that frees you from having to code one.

Im Folgenden finden Sie das allgemeine Muster für die Implementierung des Dispose-Musters für eine Basisklasse, die ein SafeHandle verwendet.Here's the general pattern for implementing the dispose pattern for a base class that uses a safe handle.

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(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(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

Hinweis

Im vorherigen Beispiel wird ein SafeFileHandle-Objekt zum Veranschaulichen des Musters verwendet; stattdessen kann auch ein beliebiges anderes von SafeHandle abgeleitetes Objekt verwendet werden.The previous example uses a SafeFileHandle object to illustrate the pattern; any object derived from SafeHandle could be used instead. Beachten Sie, dass im Beispiel das SafeFileHandle-Objekt nicht ordnungsgemäß instanziiert wird.Note that the example does not properly instantiate its SafeFileHandle object.

Im Folgenden finden Sie das allgemeine Muster für die Implementierung des Dispose-Musters für eine Basisklasse, die Object.Finalize überschreibt.Here's the general pattern for implementing the dispose pattern for a base class that overrides Object.Finalize.

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(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(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(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(False)      
   End Sub
End Class

Hinweis

In C# überschreiben Sie Object.Finalize durch Definieren eines Destruktors.In C#, you override Object.Finalize by defining a destructor.

Implementieren des Dispose-Musters für eine abgeleitete KlasseImplementing the dispose pattern for a derived class

Eine Klasse, die von einer Klasse abgeleitet ist, die die IDisposable-Schnittstelle implementiert, sollte IDisposable nicht implementieren, da die Basisklassenimplementierung von IDisposable.Dispose von den abgeleiteten Klassen geerbt wird.A class derived from a class that implements the IDisposable interface shouldn't implement IDisposable, because the base class implementation of IDisposable.Dispose is inherited by its derived classes. Stattdessen müssen Sie Folgendes bereitstellen, um das Dispose-Muster für eine abgeleitete Klasse zu implementieren:Instead, to implement the dispose pattern for a derived class, you provide the following:

  • Eine protected Dispose(Boolean)-Methode, die die Basisklassenmethode überschreibt und die eigentliche Freigabe der Ressourcen der abgeleiteten Klasse durchführt.A protected Dispose(Boolean) method that overrides the base class method and performs the actual work of releasing the resources of the derived class. Diese Methode sollte auch die Dispose(Boolean)-Methode der Basisklasse aufrufen und ihren disposing-Status für das Argument übergeben.This method should also call the Dispose(Boolean) method of the base class and pass its disposing status for the argument.

  • Entweder eine von SafeHandle abgeleitete Klasse, die die nicht verwaltete Ressource einschließt (empfohlen) oder eine Überschreibung der Object.Finalize-Methode.Either a class derived from SafeHandle that wraps your unmanaged resource (recommended), or an override to the Object.Finalize method. Die SafeHandle-Klasse stellt einen Finalizer bereit, wodurch Sie keinen programmieren müssen.The SafeHandle class provides a finalizer that frees you from having to code one. Wenn Sie einen Finalizer bereitstellen, sollte er die Dispose(Boolean)-Überladung mit einem disposing-Argument mit dem Wert false aufrufen.If you do provide a finalizer, it should call the Dispose(Boolean) overload with a disposing argument of false.

Im Folgenden finden Sie das allgemeine Muster für das Implementieren des Dispose-Musters für eine abgeleitete Klasse, die ein SafeHandle verwendet:Here's the general pattern for implementing the dispose pattern for a derived class that uses a safe handle:

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

Hinweis

Im vorherigen Beispiel wird ein SafeFileHandle-Objekt zum Veranschaulichen des Musters verwendet; stattdessen kann auch ein beliebiges anderes von SafeHandle abgeleitetes Objekt verwendet werden.The previous example uses a SafeFileHandle object to illustrate the pattern; any object derived from SafeHandle could be used instead. Beachten Sie, dass im Beispiel das SafeFileHandle-Objekt nicht ordnungsgemäß instanziiert wird.Note that the example does not properly instantiate its SafeFileHandle object.

Im Folgenden finden Sie das allgemeine Muster für das Implementieren des Dispose-Musters für eine abgeleitete Klasse, die Object.Finalize überschreibt:Here's the general pattern for implementing the dispose pattern for a derived class that overrides Object.Finalize:

using System;

class DerivedClass : BaseClass
{
   // Flag: Has Dispose already been called?
   bool disposed = false;
   
   // Protected implementation of Dispose pattern.
   protected override void Dispose(bool disposing)
   {
      if (disposed)
         return; 
      
      if (disposing) {
         // Free any other managed objects here.
         //
      }
      
      // Free any unmanaged objects here.
      //
      disposed = true;
      
      // Call the base class implementation.
      base.Dispose(disposing);
   }

   ~DerivedClass()
   {
      Dispose(false);
   }
}
Class DerivedClass : Inherits BaseClass
   ' Flag: Has Dispose already been called?
   Dim disposed As Boolean = False
   
   ' Protected implementation of Dispose pattern.
   Protected Overrides 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

      ' Call the base class implementation.
      MyBase.Dispose(disposing)
   End Sub
   
   Protected Overrides Sub Finalize()
      Dispose(False)
   End Sub 
End Class

Hinweis

In C# überschreiben Sie Object.Finalize durch Definieren eines Destruktors.In C#, you override Object.Finalize by defining a destructor.

Verwenden von SafeHandlesUsing safe handles

Das Schreiben von Code für den Finalizer eines Objekts ist eine komplexe Aufgabe, die Probleme verursachen kann, wenn sie nicht ordnungsgemäß gelöst wird.Writing code for an object's finalizer is a complex task that can cause problems if not done correctly. Daher wird empfohlen, System.Runtime.InteropServices.SafeHandle-Objekte zu erstellen, anstatt einen Finalizer zu implementieren.Therefore, we recommend that you construct System.Runtime.InteropServices.SafeHandle objects instead of implementing a finalizer.

Von der System.Runtime.InteropServices.SafeHandle-Klasse abgeleitete Klassen vereinfachen Probleme mit der Objektlebensdauer, indem sie Handles ohne Unterbrechung zuweisen und freigeben.Classes derived from the System.Runtime.InteropServices.SafeHandle class simplify object lifetime issues by assigning and releasing handles without interruption. Sie enthalten einen kritischen Finalizer, der auf jeden Fall ausgeführt wird, während eine Anwendungsdomäne entladen wird.They contain a critical finalizer that is guaranteed to run while an application domain is unloading. Weitere Informationen zu den Vorteilen bei der Verwendung von SafeHandle finden Sie unter System.Runtime.InteropServices.SafeHandle.For more information about the advantages of using a safe handle, see System.Runtime.InteropServices.SafeHandle. Die folgenden abgeleiteten Klassen im Microsoft.Win32.SafeHandles-Namespace stellen SafeHandles bereit:The following derived classes in the Microsoft.Win32.SafeHandles namespace provide safe handles:

Verwenden eines SafeHandles zum Implementieren des Dispose-Musters für eine BasisklasseUsing a safe handle to implement the dispose pattern for a base class

Das folgende Beispiel zeigt das Dispose-Muster für eine Basisklasse, DisposableStreamResource, die ein SafeHandle verwendet, um nicht verwaltete Ressourcen zu kapseln.The following example illustrates the dispose pattern for a base class, DisposableStreamResource, that uses a safe handle to encapsulate unmanaged resources. Es definiert eine DisposableResource-Klasse, die ein SafeFileHandle verwendet, um ein Stream-Objekt zu umschließen, das eine offene Datei darstellt.It defines a DisposableResource class that uses a SafeFileHandle to wrap a Stream object that represents an open file. Die DisposableResource-Methode enthält auch eine einzelne Eigenschaft, Size, die die Gesamtzahl von Bytes im Dateistream zurückgibt.The DisposableResource method also includes a single property, Size, that returns the total number of bytes in the file stream.

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

public class DisposableStreamResource : IDisposable
{
   // Define constants.
   protected const uint GENERIC_READ = 0x80000000;
   protected const uint FILE_SHARE_READ = 0x00000001;
   protected const uint OPEN_EXISTING = 3;
   protected const uint FILE_ATTRIBUTE_NORMAL = 0x80;
   protected IntPtr INVALID_HANDLE_VALUE = new IntPtr(-1);
   private const int INVALID_FILE_SIZE = unchecked((int) 0xFFFFFFFF);
   
   // Define Windows APIs.
   [DllImport("kernel32.dll", EntryPoint = "CreateFileW", CharSet = CharSet.Unicode)]
   protected static extern IntPtr CreateFile (
                                  string lpFileName, uint dwDesiredAccess, 
                                  uint dwShareMode, IntPtr lpSecurityAttributes, 
                                  uint dwCreationDisposition, uint dwFlagsAndAttributes, 
                                  IntPtr hTemplateFile);
   
   [DllImport("kernel32.dll")]
   private static extern int GetFileSize(SafeFileHandle hFile, out int lpFileSizeHigh);
    
   // Define locals.
   private bool disposed = false;
   private SafeFileHandle safeHandle; 
   private long bufferSize;
   private int upperWord;
   
   public DisposableStreamResource(string filename)
   {
      if (filename == null)
         throw new ArgumentNullException("The filename cannot be null.");
      else if (filename == "")
         throw new ArgumentException("The filename cannot be an empty string.");
            
      IntPtr handle = CreateFile(filename, GENERIC_READ, FILE_SHARE_READ,
                                 IntPtr.Zero, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL,
                                 IntPtr.Zero);
      if (handle != INVALID_HANDLE_VALUE)
         safeHandle = new SafeFileHandle(handle, true);
      else
         throw new FileNotFoundException(String.Format("Cannot open '{0}'", filename));
      
      // Get file size.
      bufferSize = GetFileSize(safeHandle, out upperWord); 
      if (bufferSize == INVALID_FILE_SIZE)
         bufferSize = -1;
      else if (upperWord > 0) 
         bufferSize = (((long)upperWord) << 32) + bufferSize;
   }
   
   public long Size 
   { get { return bufferSize; } }

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

   protected virtual void Dispose(bool disposing)
   {
      if (disposed) return;

      // Dispose of managed resources here.
      if (disposing)
         safeHandle.Dispose();
      
      // Dispose of any unmanaged resources not wrapped in safe handles.
      
      disposed = true;
   }  
}
Imports Microsoft.Win32.SafeHandles
Imports System.IO

Public Class DisposableStreamResource : Implements IDisposable
   ' Define constants.
   Protected Const GENERIC_READ As UInteger = &H80000000ui
   Protected Const FILE_SHARE_READ As UInteger = &H0000000i
   Protected Const OPEN_EXISTING As UInteger = 3
   Protected Const FILE_ATTRIBUTE_NORMAL As UInteger = &H80
   Protected INVALID_HANDLE_VALUE As New IntPtr(-1)
   Private Const INVALID_FILE_SIZE As Integer = &HFFFFFFFF
   
   ' Define Windows APIs.
   Protected Declare Function CreateFile Lib "kernel32" Alias "CreateFileA" (
                                         lpFileName As String, dwDesiredAccess As UInt32, 
                                         dwShareMode As UInt32, lpSecurityAttributes As IntPtr, 
                                         dwCreationDisposition As UInt32, dwFlagsAndAttributes As UInt32, 
                                         hTemplateFile As IntPtr) As IntPtr
   Private Declare Function GetFileSize Lib "kernel32" (hFile As SafeFileHandle, 
                                                        ByRef lpFileSizeHigh As Integer) As Integer
    
   ' Define locals.
   Private disposed As Boolean = False
   Private safeHandle As SafeFileHandle 
   Private bufferSize As Long 
   Private upperWord As Integer
   
   Public Sub New(filename As String)
      If filename Is Nothing Then
         Throw New ArgumentNullException("The filename cannot be null.")
      Else If filename = ""
         Throw New ArgumentException("The filename cannot be an empty string.")
      End If
            
      Dim handle As IntPtr = CreateFile(filename, GENERIC_READ, FILE_SHARE_READ,
                                        IntPtr.Zero, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL,
                                        IntPtr.Zero)
      If handle <> INVALID_HANDLE_VALUE Then
         safeHandle = New SafeFileHandle(handle, True)
      Else
         Throw New FileNotFoundException(String.Format("Cannot open '{0}'", filename))
      End If
      
      ' Get file size.
      bufferSize = GetFileSize(safeHandle, upperWord) 
      If bufferSize = INVALID_FILE_SIZE Then
         bufferSize = -1
      Else If upperWord > 0 Then 
         bufferSize = (CLng(upperWord) << 32) + bufferSize
      End If     
   End Sub
   
   Public ReadOnly Property Size As Long
      Get
         Return bufferSize
      End Get
   End Property
   
   Public Sub Dispose() _
              Implements IDisposable.Dispose
      Dispose(True)
      GC.SuppressFinalize(Me)
   End Sub           

   Protected Overridable Sub Dispose(disposing As Boolean)
      If disposed Then Exit Sub

      ' Dispose of managed resources here.
      If disposing Then
         safeHandle.Dispose()
      End If
      
      ' Dispose of any unmanaged resources not wrapped in safe handles.
      
      disposed = True
   End Sub  
End Class

Verwenden eines SafeHandles zum Implementieren des Dispose-Musters für eine abgeleitete KlasseUsing a safe handle to implement the dispose pattern for a derived class

Das folgende Beispiel zeigt das Dispose-Muster für eine abgeleitete Klasse, DisposableStreamResource2, die von der DisposableStreamResource-Klasse erbt, die im vorherigen Beispiel dargestellt wurde.The following example illustrates the dispose pattern for a derived class, DisposableStreamResource2, that inherits from the DisposableStreamResource class presented in the previous example. Die Klasse fügt eine zusätzliche Methode, WriteFileInfo, hinzu und verwendet ein SafeFileHandle-Objekt, um das Handle der überschreibbaren Datei zu umschließen.The class adds an additional method, WriteFileInfo, and uses a SafeFileHandle object to wrap the handle of the writable file.

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

public class DisposableStreamResource2 : DisposableStreamResource
{
   // Define additional constants.
   protected const uint GENERIC_WRITE = 0x40000000; 
   protected const uint OPEN_ALWAYS = 4;
   
   // Define additional APIs.
   [DllImport("kernel32.dll")]   
   protected static extern bool WriteFile(
                                SafeFileHandle safeHandle, string lpBuffer, 
                                int nNumberOfBytesToWrite, out int lpNumberOfBytesWritten,
                                IntPtr lpOverlapped);
   
   // Define locals.
   private bool disposed = false;
   private string filename;
   private bool created = false;
   private SafeFileHandle safeHandle;
   
   public DisposableStreamResource2(string filename) : base(filename)
   {
      this.filename = filename;
   }
   
   public void WriteFileInfo()
   { 
      if (! created) {
         IntPtr hFile = CreateFile(@".\FileInfo.txt", GENERIC_WRITE, 0, 
                                   IntPtr.Zero, OPEN_ALWAYS, 
                                   FILE_ATTRIBUTE_NORMAL, IntPtr.Zero);
         if (hFile != INVALID_HANDLE_VALUE)
            safeHandle = new SafeFileHandle(hFile, true);
         else
            throw new IOException("Unable to create output file.");

         created = true;
      }

      string output = String.Format("{0}: {1:N0} bytes\n", filename, Size);
      int bytesWritten;
      bool result = WriteFile(safeHandle, output, output.Length, out bytesWritten, IntPtr.Zero);                                     
   }

   protected override void Dispose(bool disposing)
   {
      if (disposed) return;
      
      // Release any managed resources here.
      if (disposing)
         safeHandle.Dispose();
      
      disposed = true;
      
      // Release any unmanaged resources not wrapped by safe handles here.
      
      // Call the base class implementation.
      base.Dispose(disposing);
   }
}
Imports Microsoft.Win32.SafeHandles
Imports System.IO

Public Class DisposableStreamResource2 : Inherits DisposableStreamResource
   ' Define additional constants.
   Protected Const GENERIC_WRITE As Integer = &H40000000 
   Protected Const OPEN_ALWAYS As Integer = 4
   
   ' Define additional APIs.
   Protected Declare Function WriteFile Lib "kernel32.dll" (
                              safeHandle As SafeFileHandle, lpBuffer As String, 
                              nNumberOfBytesToWrite As Integer, ByRef lpNumberOfBytesWritten As Integer,
                              lpOverlapped As Object) As Boolean
   
   ' Define locals.
   Private disposed As Boolean = False
   Private filename As String
   Private created As Boolean = False
   Private safeHandle As SafeFileHandle
   
   Public Sub New(filename As String)
      MyBase.New(filename)
      Me.filename = filename
   End Sub
   
   Public Sub WriteFileInfo() 
      If Not created Then
         Dim hFile As IntPtr = CreateFile(".\FileInfo.txt", GENERIC_WRITE, 0, 
                                          IntPtr.Zero, OPEN_ALWAYS, 
                                          FILE_ATTRIBUTE_NORMAL, IntPtr.Zero)
         If hFile <> INVALID_HANDLE_VALUE Then
            safeHandle = New SafeFileHandle(hFile, True)
         Else
            Throw New IOException("Unable to create output file.")
         End If
         created = True
      End If
      Dim output As String = String.Format("{0}: {1:N0} bytes {2}", filename, Size, 
                                           vbCrLf)
      WriteFile(safeHandle, output, output.Length, 0&, Nothing)                                     
   End Sub

   Protected Overloads Overridable Sub Dispose(disposing As Boolean)
      If disposed Then Exit Sub
      
      ' Release any managed resources here.
      If disposing Then
         safeHandle.Dispose()
      End If
      
      disposed = True
      ' Release any unmanaged resources not wrapped by safe handles here.
      
      ' Call the base class implementation.
      MyBase.Dispose(disposing)
   End Sub
End Class

Siehe auchSee also