L'istruzione using in C#

Nella lezione precedente abbiamo parlato della clausola finally e di come possiamo usarla per garantire che le risorse vengano sempre rilasciate, anche se si verifica un'eccezione o viene eseguita un'istruzione return all'interno del blocco try.

Esiste, tuttavia, un modo più semplice e conveniente per gestire le risorse in C# utilizzando l'istruzione using.

Tuttavia, l'istruzione using non pulisce qualsiasi tipo di risorsa, ma solo quelle che implementano l'interfaccia IDisposable. In questa lezione, esploreremo l'interfaccia IDisposable, il suo scopo e come utilizzare l'istruzione using per gestire le risorse in modo efficace.

Concetti Chiave
  • L'istruzione using in C# è utilizzata per gestire le risorse che implementano l'interfaccia IDisposable.
  • L'interfaccia IDisposable fornisce un metodo chiamato Dispose() che viene utilizzato per rilasciare le risorse allocate da una classe.
  • L'istruzione using semplifica la gestione delle risorse, garantendo che le risorse vengano rilasciate automaticamente al termine del blocco using.
  • È consigliabile utilizzare l'istruzione using con tutte le classi che implementano l'interfaccia IDisposable per garantire il rilascio corretto delle risorse.

L'Interfaccia IDisposable

L'uso principale dell'interfaccia IDisposable è rilasciare risorse.

In .NET tali risorse sono handle di finestre, file, stream e altri oggetti.

Non entreremo nei dettagli su come implementare IDisposable poiché dobbiamo andare molto più in profondità e spiegare come funziona il garbage collector, come usare i distruttori, le risorse non gestite e così via.

Il metodo importante nell'interfaccia IDisposable è Dispose(). La cosa principale che dobbiamo sapere sul metodo è che rilascia le risorse della classe che lo implementa. Nei casi in cui le risorse sono stream, reader o file, il rilascio delle risorse può essere fatto usando il metodo Dispose() dall'interfaccia IDisposable, che chiama il loro metodo Close(). Questo metodo li chiude e rilascia le loro risorse. Quindi per chiudere uno stream possiamo fare quanto segue:

StreamReader lettore = new StreamReader(nomeFile);

try
{
    // Usa il lettore qui
}
finally
{
    if (lettore != null)
    {
        lettore.Dispose();
    }
}

L'istruzione using

L'esempio precedente può essere scritto in forma più breve con l'aiuto della parola chiave using in C#, come mostrato nell'esempio seguente:

using (StreamReader lettore = new StreamReader(nomeFile))
{
    // Usa il lettore qui
}

La forma semplificata del "pattern dispose" sopra riportata è semplice da scrivere, semplice da usare e semplice da leggere. Inoltre garantisce il rilascio corretto delle risorse allocate specificate nelle parentesi dell'istruzione using.

Non è necessario avere try-finally o chiamare esplicitamente alcun metodo per rilasciare le risorse. Il compilatore si occupa di inserire automaticamente il blocco try-finally e le risorse utilizzate vengono rilasciate chiamando il metodo Dispose() dopo aver lasciato il blocco using.

Più avanti nelle lezioni successive utilizzeremo estensivamente l'istruzione using per leggere e scrivere correttamente i file di testo.

Istruzioni using nidificate

Le istruzioni using possono essere nidificate una dentro l'altra:

using (TipoRisorsa r1 = ...)
    using (TipoRisorsa r2 = ...)
        /* ... */
            using (TipoRisorsa rN = ...)
                {
                    istruzioni;
                }

In alternativa, possiamo dichiarare più risorse in un'unica istruzione using:

using (TipoRisorsa r1 = ..., r2 = ..., ..., rN = ...)
{
    istruzioni;
}

È importante menzionare che l'istruzione using non è correlata alla gestione delle eccezioni. Il suo unico scopo è rilasciare le risorse indipendentemente dal fatto che vengano lanciate eccezioni o meno.

Non gestisce le eccezioni.

Pertanto, possiamo usare comunque un blocco try-catch all'interno di un blocco using per gestire le eccezioni, se necessario. Ad esempio:

using (StreamReader lettore = new StreamReader(nomeFile))
{
    try
    {
        // Usa il lettore qui
    }
    catch (Exception ex)
    {
        // Gestisci l'eccezione qui
    }
}

Come si può osservare, l'istruzione using semplifica notevolmente la gestione delle risorse in C#, rendendo il codice più pulito e leggibile. Non abbiamo avuto il bisogno di aggiungere una clausola finally per rilasciare le risorse, poiché l'istruzione using si occupa automaticamente di questo.

Quando Usare l'Istruzione using

Esiste una regola semplice su quando usare using con le classi .NET:

Consiglio

Regola per l'uso di using

Utilizzare l'istruzione using con tutte le classi che implementano l'interfaccia IDisposable.

Cercare IDisposable in MSDN.

Quando una classe implementa l'interfaccia IDisposable questo significa che il creatore di questa classe si aspetta che possa essere utilizzata con l'istruzione using e la classe contiene qualche risorsa costosa che non dovrebbe essere lasciata non rilasciata.

Implementare IDisposable significa anche che dovrebbe essere rilasciata immediatamente dopo aver finito di usare la classe e il modo più semplice per farlo in C# è con l'istruzione using.