Implementazione di un metodo DisposeImplementing a Dispose method

Implementare un metodo Dispose per rilasciare le risorse non gestite usate dall'applicazione.You implement a Dispose method to release unmanaged resources used by your application. Garbage Collector di .NET non alloca e non rilascia la memoria non gestita.The .NET garbage collector does not allocate or release unmanaged memory.

Il criterio per eliminare un oggetto, definito criterio Dispose, definisce un ordine in base alla durata di un oggetto.The pattern for disposing an object, referred to as a dispose pattern, imposes order on the lifetime of an object. Il modello Dispose viene usato solo per gli oggetti che accedono a risorse non gestite, quali handle di file e pipe, handle del Registro di sistema, handle di attesa o puntatori ai blocchi di memoria non gestita.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. Ciò è dovuto al fatto che il Garbage Collector è molto efficiente nel recupero degli oggetti gestiti inutilizzati, ma non è in grado di recuperare gli oggetti non gestiti.This is because the garbage collector is very efficient at reclaiming unused managed objects, but it is unable to reclaim unmanaged objects.

Il modello Dispose precede due variazioni:The dispose pattern has two variations:

Al fine di garantire la corretta pulitura delle risorse in ogni occasione, deve essere possibile chiamare il metodo Dispose più volte senza che venga generata un'eccezione.To help ensure that resources are always cleaned up appropriately, a Dispose method should be callable multiple times without throwing an exception.

L'esempio di codice fornito per il metodo GC.KeepAlive illustra come una procedura di Garbage Collection troppo incisiva possa determinare l'esecuzione di un finalizzatore mentre un membro dell'oggetto recuperato è ancora in esecuzione.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. È consigliabile chiamare il metodo KeepAlive alla fine di un metodo Dispose di lunga durata.It is a good idea to call the KeepAlive method at the end of a lengthy Dispose method.

Dispose() e Dispose(Boolean)Dispose() and Dispose(Boolean)

L'interfaccia IDisposable richiede l'implementazione di un singolo metodo senza parametri, Dispose.The IDisposable interface requires the implementation of a single parameterless method, Dispose. Tuttavia, il modello Dispose richiede due metodi Dispose per essere implementato:However, the dispose pattern requires two Dispose methods to be implemented:

  • Un'implementazione NonInheritable pubblica non virtuale (IDisposable.Dispose in Visual Basic) senza parametri.A public non-virtual (NonInheritable in Visual Basic) IDisposable.Dispose implementation that has no parameters.

  • Un metodo Overridable protetto virtuale (Dispose in Visual Basic) la cui firma è indicata di seguito: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)
    

Overload Dispose()The Dispose() overload

Poiché il metodo pubblico, non virtuale (NonInheritable in Visual Basic), privo di parametri Dispose è chiamato da un consumer del tipo, lo scopo è liberare le risorse non gestite e indicare che non è necessario eseguire il finalizzatore, se disponibili.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. Per questo motivo il metodo ha un'implementazione standard: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

Il metodo Dispose esegue la pulizia di tutti gli oggetti, quindi il Garbage Collector non deve più chiamare l'override Object.Finalize degli oggetti.The Dispose method performs all object cleanup, so the garbage collector no longer needs to call the objects' Object.Finalize override. Pertanto, la chiamata al metodo SuppressFinalize impedisce al Garbage Collector di eseguire il finalizzatore.Therefore, the call to the SuppressFinalize method prevents the garbage collector from running the finalizer. Se il tipo non dispone di un finalizzatore, la chiamata a GC.SuppressFinalize non ha alcun effetto.If the type has no finalizer, the call to GC.SuppressFinalize has no effect. Si noti che l'effettiva operazione di rilascio delle risorse non gestite viene eseguita dal secondo overload del metodo Dispose.Note that the actual work of releasing unmanaged resources is performed by the second overload of the Dispose method.

Overload Dispose(Boolean)The Dispose(Boolean) overload

Nel secondo overload il parametro disposing è un oggetto Boolean che indica se la chiamata al metodo proviene da un metodo Dispose (il valore è true) o da un finalizzatore (il valore è false).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).

Il corpo del metodo è costituito da due blocchi di codice:The body of the method consists of two blocks of code:

  • Un blocco che libera le risorse non gestite.A block that frees unmanaged resources. Questo blocco viene eseguito indipendentemente dal valore del parametro disposing.This block executes regardless of the value of the disposing parameter.

  • Un blocco condizionale che libera le risorse gestite.A conditional block that frees managed resources. Il blocco è eseguito se il valore di disposing è true.This block executes if the value of disposing is true. Le risorse gestite liberate possono includere:The managed resources that it frees can include:

    Oggetti gestiti che implementano IDisposable.Managed objects that implement IDisposable. Il blocco condizionale può essere usato per chiamare la relativa implementazione Dispose.The conditional block can be used to call their Dispose implementation. Se è stato usato un handle sicuro per eseguire il wrapping della risorsa non gestita, l'implementazione SafeHandle.Dispose(Boolean) dovrebbe essere chiamata in questo punto.If you have used a safe handle to wrap your unmanaged resource, you should call the SafeHandle.Dispose(Boolean) implementation here.

    Oggetti gestiti che usano grandi quantità di memoria o risorse insufficienti.Managed objects that consume large amounts of memory or consume scarce resources. La liberazione esplicita di questi oggetti nel metodo Dispose ne consente un rilascio più veloce rispetto al recupero non deterministico eseguito dal Garbage Collector.Freeing these objects explicitly in the Dispose method releases them faster than if they were reclaimed non-deterministically by the garbage collector.

Se la chiamata al metodo proviene da un finalizzatore (ovvero se disposing è false), viene eseguito solo il codice che libera le risorse non gestite.If the method call comes from a finalizer (that is, if disposing is false), only the code that frees unmanaged resources executes. Poiché l'ordine in cui il Garbage Collector elimina gli oggetti gestiti durante la finalizzazione non è definito, la chiamata a questo overload Dispose con valore false impedisce che il finalizzatore tenti di liberare risorse gestite che potrebbero essere già state recuperate.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.

Implementazione del modello Dispose per una classe di baseImplementing the dispose pattern for a base class

Per implementare il modello Dispose per una classe di base, è necessario predisporre quanto segue:If you implement the dispose pattern for a base class, you must provide the following:

Importante

È consigliabile implementare questo modello per tutte le classi di base che implementano Dispose() e non sono sealed (NotInheritable in Visual Basic).You should implement this pattern for all base classes that implement Dispose() and are not sealed (NotInheritable in Visual Basic).

  • Un'implementazione Dispose che chiami il metodo Dispose(Boolean).A Dispose implementation that calls the Dispose(Boolean) method.

  • Un metodo Dispose(Boolean) che esegua l'effettiva operazione di rilascio delle risorse.A Dispose(Boolean) method that performs the actual work of releasing resources.

  • Una classe derivata da SafeHandle che esegua il wrapping della risorsa non gestita (consigliato) o un override al metodo Object.Finalize.Either a class derived from SafeHandle that wraps your unmanaged resource (recommended), or an override to the Object.Finalize method. La classe SafeHandle fornisce un finalizzatore, evitando la necessità di codificarne uno.The SafeHandle class provides a finalizer that frees you from having to code one.

Di seguito è illustrato il modello generale per implementare il modello Dispose per una classe di base che usa un handle sicuro.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

Nota

L'esempio precedente usa un oggetto SafeFileHandle per illustrato il criterio; sarebbe possibile usare invece qualsiasi oggetto derivato da SafeHandle.The previous example uses a SafeFileHandle object to illustrate the pattern; any object derived from SafeHandle could be used instead. Si noti che l'esempio non crea correttamente un'istanza del relativo oggetto SafeFileHandle.Note that the example does not properly instantiate its SafeFileHandle object.

Di seguito è illustrato il modello generale per implementare il modello Dispose per una classe di base che esegue l'override di Object.Finalize.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

Nota

In C# si esegue l'override di Object.Finalize definendo un distruttore.In C#, you override Object.Finalize by defining a destructor.

Implementazione del modello Dispose per una classe derivataImplementing the dispose pattern for a derived class

Una classe derivata da una classe che implementa l'interfaccia IDisposable non deve implementare IDisposable, poiché l'implementazione della classe di base di IDisposable.Dispose viene ereditata dalle classi derivate.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. Al contrario, per implementare il modello Dispose per una classe derivata, è necessario predisporre quanto segue:Instead, to implement the dispose pattern for a derived class, you provide the following:

  • Un metodo protected Dispose(Boolean) che esegua l'override del metodo della classe di base ed esegua l'effettiva operazione di rilascio delle risorse della classe derivata.A protected Dispose(Boolean) method that overrides the base class method and performs the actual work of releasing the resources of the derived class. Questo metodo deve anche chiamare il metodo Dispose(Boolean) della classe di base e passare un valore true per l'argomento disposing.This method should also call the Dispose(Boolean) method of the base class and pass it a value of true for the disposing argument.

  • Una classe derivata da SafeHandle che esegua il wrapping della risorsa non gestita (consigliato) o un override al metodo Object.Finalize.Either a class derived from SafeHandle that wraps your unmanaged resource (recommended), or an override to the Object.Finalize method. La classe SafeHandle fornisce un finalizzatore, evitando la necessità di codificarne uno.The SafeHandle class provides a finalizer that frees you from having to code one. Se si specifica un finalizzatore, questo deve chiamare l'overload di Dispose(Boolean) con un argomento disposing di false.If you do provide a finalizer, it should call the Dispose(Boolean) overload with a disposing argument of false.

Di seguito è illustrato il modello generale per implementare il modello Dispose per una classe derivata che usa un handle sicuro: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

Nota

L'esempio precedente usa un oggetto SafeFileHandle per illustrato il criterio; sarebbe possibile usare invece qualsiasi oggetto derivato da SafeHandle.The previous example uses a SafeFileHandle object to illustrate the pattern; any object derived from SafeHandle could be used instead. Si noti che l'esempio non crea correttamente un'istanza del relativo oggetto SafeFileHandle.Note that the example does not properly instantiate its SafeFileHandle object.

Di seguito è illustrato il modello generale per implementare il modello Dispose per una classe derivata che esegue l'override di Object.Finalize: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

Nota

In C# si esegue l'override di Object.Finalize definendo un distruttore.In C#, you override Object.Finalize by defining a destructor.

Utilizzo degli handle sicuriUsing safe handles

La scrittura di codice per il finalizzatore di un oggetto è un'attività complessa che può causare problemi se non eseguita correttamente.Writing code for an object's finalizer is a complex task that can cause problems if not done correctly. È pertanto consigliabile costruire oggetti System.Runtime.InteropServices.SafeHandle anziché implementare un finalizzatore.Therefore, we recommend that you construct System.Runtime.InteropServices.SafeHandle objects instead of implementing a finalizer.

Le classi derivate dalla classe System.Runtime.InteropServices.SafeHandle semplificano i problemi di durata degli oggetti assegnando e rilasciando handle senza interruzione.Classes derived from the System.Runtime.InteropServices.SafeHandle class simplify object lifetime issues by assigning and releasing handles without interruption. Contengono un finalizzatore critico la cui esecuzione è garantita durante lo scaricamento di un dominio dell'applicazione.They contain a critical finalizer that is guaranteed to run while an application domain is unloading. Per altre informazioni sui vantaggi dell'utilizzo di un handle sicuro, vedere System.Runtime.InteropServices.SafeHandle.For more information about the advantages of using a safe handle, see System.Runtime.InteropServices.SafeHandle. Le seguenti classi derivate nello spazio dei nomi Microsoft.Win32.SafeHandles forniscono handle sicuri:The following derived classes in the Microsoft.Win32.SafeHandles namespace provide safe handles:

Utilizzo di un handle sicuro per implementare il modello Dispose per una classe di baseUsing a safe handle to implement the dispose pattern for a base class

L'esempio seguente illustra il modello Dispose per una classe di base, DisposableStreamResource, che usa handle sicuri per incapsulare le risorse non gestite.The following example illustrates the dispose pattern for a base class, DisposableStreamResource, that uses a safe handle to encapsulate unmanaged resources. Viene definita una classe DisposableResource che usa SafeFileHandle per eseguire il wrapping di un oggetto Stream che rappresenta un file aperto.It defines a DisposableResource class that uses a SafeFileHandle to wrap a Stream object that represents an open file. Il metodo DisposableResource include anche una singola proprietà, Size, che restituisce il numero totale di byte nel flusso di file.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

Utilizzo di un handle sicuro per implementare il modello Dispose per una classe derivataUsing a safe handle to implement the dispose pattern for a derived class

Nell'esempio seguente viene illustrato il modello Dispose per una classe derivata, DisposableStreamResource2, che eredita dalla classe DisposableStreamResource presentata nell'esempio precedente.The following example illustrates the dispose pattern for a derived class, DisposableStreamResource2, that inherits from the DisposableStreamResource class presented in the previous example. La classe aggiunge un metodo aggiuntivo, WriteFileInfo, e usa un oggetto SafeFileHandle per il wrapping dell'handle del file modificabile.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 new virtual 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(true);
   }
}
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(True)
   End Sub
End Class

Vedere ancheSee also

SuppressFinalize
IDisposable
IDisposable.Dispose
Microsoft.Win32.SafeHandles
System.Runtime.InteropServices.SafeHandle
Object.Finalize
Procedura: Definire e usare classi e struct (C++/CLI) How to: Define and Consume Classes and Structs (C++/CLI)
Criterio DisposeDispose Pattern