Condividi tramite


Implementazione dei metodi Finalize e Dispose per la pulitura delle risorse non gestite

Nota

Per informazioni sulla finalizzazione e sull'eliminazione di risorse in C++, vedere Destructors and Finalizers in Visual C++.

Le istanze delle classi spesso incapsulano il controllo sulle risorse che non sono gestite dall'ambiente di esecuzione, quali handle delle finestre (HWND), connessioni al database e così via. È necessario quindi garantire un modo esplicito e uno implicito per liberare tali risorse. Fornire il controllo implicito implementando il metodo Finalize protetto su un oggetto (sintassi del distruttore in C# e C++). Il Garbage Collector chiama questo metodo in un momento qualsiasi, una volta determinata la mancanza di eventuali ulteriori riferimenti validi all'oggetto.

In alcuni casi è possibile consentire ai programmatori che utilizzano un oggetto di rilasciare in modo esplicito le risorse esterne prima che il Garbage Collector liberi l'oggetto. Se una risorsa esterna è scarsa o costosa, è possibile ottenere prestazioni migliori se il programmatore rilascia le risorse in modo esplicito quando non vengono più utilizzate. Per fornire il controllo esplicito, implementare il metodo Dispose fornito dall'interfaccia IDisposable. Una volta terminato l'utilizzo dell'oggetto, il consumer deve chiamare questo metodo. È possibile chiamare il metodo Dispose anche se sono attivi altri riferimenti all'oggetto.

Si noti che anche quando si fornisce il controllo esplicito utilizzando il metodo Dispose, è necessario fornire la pulitura implicita utilizzando il metodo Finalize. Il metodo Finalize fornisce un meccanismo di backup per evitare che le risorse vengano perdute definitivamente se non viene eseguita correttamente la chiamata al metodo Dispose.

Per ulteriori informazioni sull'implementazione dei metodi Finalize e Dispose per la pulitura delle risorse non gestite, vedere Garbage Collection. Nell'esempio di codice riportato di seguito viene illustrato il modello di progettazione di base per l'implementazione del metodo Dispose . Per questo esempio è necessario lo spazio dei nomi System.

' Design pattern for a base class.

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

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

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

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

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

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

Per un esempio di codice più dettagliato in cui viene illustrato il modello di progettazione per l'implementazione dei metodi Finalize e Dispose, vedere Implementazione di un metodo Dispose.

Personalizzazione del nome di un metodo Dispose

In alcuni casi è più appropriato utilizzare per il dominio un nome specifico anziché Dispose. Per l'incapsulamento di un file, ad esempio, è possibile utilizzare il nome di metodo Close. In questo caso, implementare il metodo Dispose in modo privato e creare un metodo Close pubblico che chiami il metodo Dispose. Nell'esempio di codice seguente viene illustrato questo modello. È possibile sostituire Close con il nome di un metodo appropriato per il dominio. Per questo esempio è necessario lo spazio dei nomi System.

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

Finalize

Di seguito sono riportate le linee guida per l'utilizzo del metodo Finalize:

  • Implementare il metodo Finalize solo su oggetti che richiedono il completamento. Ai metodi Finalize vengono associati alcuni costi in termini di prestazioni.

  • Se è necessario utilizzare un metodo Finalize, è possibile implementare IDisposable per evitare agli utenti della classe la necessità di richiamare il metodo Finalize.

  • Non rendere il metodo Finalize più visibile. Il metodo deve essere protetto e non pubblico.

  • Il metodo Finalize di un oggetto deve essere libero da qualsiasi risorsa esterna di proprietà dell'oggetto. Deve inoltre liberare solo le risorse mantenute dall'oggetto. Il metodo Finalize non deve far riferimento ad altri oggetti.

  • Non chiamare direttamente un metodo Finalize su un oggetto diverso dalla classe base dell'oggetto. Questa operazione non è valida nel linguaggio di programmazione C#.

  • Chiamare il metodo Finalize della classe base dal metodo Finalize di un oggetto.

    Nota

    Il metodo Finalize della classe base viene chiamato automaticamente insieme alla sintassi dei distruttori C# e C++.

Dispose

Di seguito sono riportate le linee guida per l'utilizzo del metodo Dispose:

  • Implementare il modello di progettazione del metodo Dispose su un tipo che incapsula le risorse che devono essere liberate in modo esplicito. Gli utenti possono liberare le risorse esterne chiamando il metodo Dispose pubblico.

  • Implementare il modello di progettazione del metodo Dispose su un tipo base che in genere dispone di tipi derivati che contengono le risorse anche se il tipo base non le contiene. Se il tipo base dispone di un metodo Close, è probabile che sia necessario implementare il metodo Dispose. In questi casi non implementare un metodo Finalize sul tipo base. È necessario implementare Finalize in qualsiasi tipo derivato che introduce risorse che richiedono la pulitura.

  • Liberare le risorse eliminabili che possiede un tipo nel proprio metodo Dispose.

  • Dopo aver chiamato il metodo Dispose su un'istanza, impedire l'esecuzione del metodo Finalize chiamando il metodo GC.SuppressFinalize. L'eccezione a tale regola è rappresentata dai rari casi in cui è necessario eseguire operazioni nel metodo Finalize che non rientrano nel metodo Dispose.

  • Chiamare il metodo Dispose della classe base se viene implementata l'interfaccia IDisposable.

  • Non presupporre che verrà chiamato il metodo Dispose. Le risorse non gestite appartenenti a un tipo devono essere liberate in un metodo Finalize nel caso in cui il metodo Dispose non venga chiamato.

  • Generare un'eccezione ObjectDisposedException dai metodi di istanza del tipo, tranne Dispose, se le risorse sono già state eliminate. Questa regola non viene applicata al metodo Dispose, che deve poter essere chiamato più volte senza che venga generata un'eccezione.

  • Propagare le chiamate al metodo Dispose attraverso la gerarchia dei tipi base. Il metodo Dispose deve liberare tutte le risorse utilizzate da questo oggetto e da qualsiasi oggetto appartenente a quest'ultimo. È possibile, ad esempio, creare un oggetto quale TextReader contenente sia Stream che Encoding, entrambi creati automaticamente dall'oggetto TextReader. Sia Stream che Encoding possono inoltre acquisire risorse esterne. Quando si chiama il metodo Dispose su TextReader, è necessario che quest'ultimo chiami a sua volta il metodo Dispose su Stream e Encoding affinché liberino le rispettive risorse esterne.

  • Dopo che è stato chiamato il metodo Dispose relativo a un oggetto, può essere opportuno impedire l'utilizzo dell'oggetto. La rigenerazione di un oggetto già eliminato è un modello di difficile implementazione.

  • Consentire più chiamate di un metodo Dispose senza che venga generata un'eccezione. Il metodo non deve eseguire alcuna operazione dopo la prima chiamata.

Portions Copyright 2005 Microsoft Corporation. Tutti i diritti riservati.

Portions Copyright Addison-Wesley Corporation. Tutti i diritti riservati.

Per ulteriori informazioni sulle linee guida di progettazione, consultare il testo "Framework Design Guidelines: Conventions, Idioms, and Patterns for Reusable .NET Libraries" di Krzysztof Cwalina e Brad Abrams, edito da Addison-Wesley, 2005.

Vedere anche

Riferimenti

IDisposable.Dispose Method
Object.Finalize Method

Altre risorse

Linee guida di progettazione per lo sviluppo di librerie di classi
Garbage Collection
Modelli di progettazione