C# Language
Interfaccia IDisposable
Ricerca…
Osservazioni
Spetta ai client della classe che implementano
IDisposable
per assicurarsi che chiamino il metodoDispose
quando hanno finito di utilizzare l'oggetto. Non c'è nulla nel CLR che cerca direttamente oggetti per un metodoDispose
da richiamare.Non è necessario implementare un finalizzatore se l'oggetto contiene solo risorse gestite. Assicurati di chiamare
Dispose
su tutti gli oggetti che la tua classe usa quando implementi il tuo metodo diDispose
.Si consiglia di rendere la classe sicura contro più chiamate a
Dispose
, sebbene dovrebbe idealmente essere chiamata una sola volta. Questo può essere ottenuto aggiungendo una variabileprivate bool
alla classe e impostando il valore sutrue
quando è stato eseguito il metodoDispose
.
In una classe che contiene solo risorse gestite
Le risorse gestite sono risorse che il garbage collector del runtime è a conoscenza e sotto il controllo di. Esistono molte classi disponibili nel BCL, ad esempio, come SqlConnection
che è una classe wrapper per una risorsa non gestita. Queste classi implementano già l'interfaccia IDisposable
- IDisposable
dal tuo codice per ripulirle quando hai finito.
Non è necessario implementare un finalizzatore se la tua classe contiene solo risorse gestite.
public class ObjectWithManagedResourcesOnly : IDisposable
{
private SqlConnection sqlConnection = new SqlConnection();
public void Dispose()
{
sqlConnection.Dispose();
}
}
In una classe con risorse gestite e non gestite
È importante lasciare che la finalizzazione ignori le risorse gestite. Il finalizzatore viene eseguito su un altro thread: è possibile che gli oggetti gestiti non esistano più al momento dell'esecuzione del finalizzatore. L'implementazione di un metodo Dispose(bool)
protetto Dispose(bool)
è una pratica comune per garantire che le risorse gestite non abbiano il loro metodo Dispose
chiamato da un finalizzatore.
public class ManagedAndUnmanagedObject : IDisposable
{
private SqlConnection sqlConnection = new SqlConnection();
private UnmanagedHandle unmanagedHandle = Win32.SomeUnmanagedResource();
private bool disposed;
public void Dispose()
{
Dispose(true); // client called dispose
GC.SuppressFinalize(this); // tell the GC to not execute the Finalizer
}
protected virtual void Dispose(bool disposeManaged)
{
if (!disposed)
{
if (disposeManaged)
{
if (sqlConnection != null)
{
sqlConnection.Dispose();
}
}
unmanagedHandle.Release();
disposed = true;
}
}
~ManagedAndUnmanagedObject()
{
Dispose(false);
}
}
IDisposable, Dispose
.NET Framework definisce un'interfaccia per i tipi che richiedono un metodo di rimozione:
public interface IDisposable
{
void Dispose();
}
Dispose()
viene utilizzato principalmente per la pulizia delle risorse, come i riferimenti non gestiti. Tuttavia, può anche essere utile forzare lo smaltimento di altre risorse anche se sono gestite. Invece di aspettare che il GC risolva anche la tua connessione al database, puoi assicurarti che sia fatto nella tua implementazione di Dispose()
.
public void Dispose()
{
if (null != this.CurrentDatabaseConnection)
{
this.CurrentDatabaseConnection.Dispose();
this.CurrentDatabaseConnection = null;
}
}
Quando è necessario accedere direttamente alle risorse non gestite come puntatori non gestiti o risorse win32, creare una classe ereditata da SafeHandle
e utilizzare le convenzioni / gli strumenti di quella classe per farlo.
In una classe ereditata con risorse gestite
È abbastanza comune che sia possibile creare una classe che implementa IDisposable
e quindi derivare classi che contengono anche risorse gestite. Si consiglia di contrassegnare il metodo Dispose
con la parola chiave virtual
modo che i client abbiano la possibilità di ripulire tutte le risorse che possono possedere.
public class Parent : IDisposable
{
private ManagedResource parentManagedResource = new ManagedResource();
public virtual void Dispose()
{
if (parentManagedResource != null)
{
parentManagedResource.Dispose();
}
}
}
public class Child : Parent
{
private ManagedResource childManagedResource = new ManagedResource();
public override void Dispose()
{
if (childManagedResource != null)
{
childManagedResource.Dispose();
}
//clean up the parent's resources
base.Dispose();
}
}
usando la parola chiave
Quando un oggetto implementa l'interfaccia IDisposable
, può essere creato all'interno della sintassi using
:
using (var foo = new Foo())
{
// do foo stuff
} // when it reaches here foo.Dispose() will get called
public class Foo : IDisposable
{
public void Dispose()
{
Console.WriteLine("dispose called");
}
}
using
è zucchero sintetico per un blocco try/finally
; l'utilizzo di cui sopra si tradurrebbe approssimativamente in:
{
var foo = new Foo();
try
{
// do foo stuff
}
finally
{
if (foo != null)
((IDisposable)foo).Dispose();
}
}