Ricerca…


Osservazioni

  • Spetta ai client della classe che implementano IDisposable per assicurarsi che chiamino il metodo Dispose quando hanno finito di utilizzare l'oggetto. Non c'è nulla nel CLR che cerca direttamente oggetti per un metodo Dispose 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 di Dispose .

  • 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 variabile private bool alla classe e impostando il valore su true quando è stato eseguito il metodo Dispose .

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");
    }
}

Guarda la demo

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();
    }
}


Modified text is an extract of the original Stack Overflow Documentation
Autorizzato sotto CC BY-SA 3.0
Non affiliato con Stack Overflow