IDisposable e istruzione using
Fa parte della sezione Programmazione orientata agli oggetti del percorso C# di Coddy. Lezione 45 di 70.
Alcuni oggetti mantengono risorse che il garbage collector non può liberare automaticamente: handle di file, connessioni al database, socket di rete. L'interfaccia IDisposable fornisce un modo standard per rilasciare queste risorse quando hai finito di usarle.
Una classe implementa IDisposable fornendo un metodo Dispose():
public class FileHandler : IDisposable
{
private bool disposed = false;
public void Dispose()
{
if (!disposed)
{
Console.WriteLine("Releasing resources...");
disposed = true;
}
}
}Potresti chiamare Dispose() manualmente, ma cosa succede se si verifica un'eccezione prima di raggiungere quella riga? L'istruzione using garantisce che la pulizia avvenga, anche quando qualcosa va storto:
using (FileHandler handler = new FileHandler())
{
// Lavora con il gestore
} // Dispose() viene chiamato automaticamente quiIl C# moderno offre una sintassi più pulita con la dichiarazione using, che elimina l’oggetto quando esce dall’ambito:
void ProcessFile()
{
using FileHandler handler = new FileHandler();
// Lavora con handler
} // Dispose() viene chiamato quando il metodo terminaL'istruzione using funziona con qualsiasi tipo che implementi IDisposable. Le classi integrate come StreamReader, SqlConnection e HttpClient implementano tutte questa interfaccia, rendendo la gestione corretta delle risorse semplice e affidabile.
Sfida
FacileCostruiamo un simulatore di connessione a un database che dimostri la corretta gestione delle risorse usando l'interfaccia IDisposable e l'istruzione using. Creerai una classe che tiene traccia dell'apertura e della chiusura delle connessioni, assicurando che le risorse vengano sempre rilasciate correttamente.
Organizzerai il codice in due file:
DatabaseConnection.cs: crea una classeDatabaseConnectionnello spazio dei nomiDataAccessche implementiIDisposable. La connessione dovrà:- Avere una proprietà
ConnectionName(stringa, di sola lettura) impostata tramite il costruttore - Tenere traccia del fatto che la connessione sia stata eliminata usando un campo booleano privato
- Stampare
Connection opened: {ConnectionName}alla creazione dell'oggetto (nel costruttore) - Implementare il metodo
Dispose()per stampareConnection closed: {ConnectionName}- ma solo se non è già stata eliminata (per evitare una doppia eliminazione) - Avere un metodo
Query(string sql)che restituiscaExecuting on {ConnectionName}: {sql}
- Avere una proprietà
Program.cs: nel file principale, dimostra la corretta gestione delle risorse usando l'istruzioneusingcon la connessione al database. Crea una connessione, esegui una query e lascia che il bloccousingsi occupi automaticamente della pulizia.
Riceverai due input:
- Il nome della connessione (ad es.,
MainDB) - La query SQL da eseguire (ad es.,
SELECT * FROM Users)
Usa un'istruzione using per creare la connessione. All'interno del blocco, chiama il metodo Query e stampa il risultato. Quando il blocco using termina, Dispose() verrà chiamato automaticamente.
Ad esempio, se gli input sono MainDB e SELECT * FROM Users, l'output dovrebbe essere:
Connection opened: MainDB
Executing on MainDB: SELECT * FROM Users
Connection closed: MainDBNota come la connessione venga chiusa automaticamente quando il blocco using termina: non dovrai mai ricordarti di chiamare manualmente Dispose(). Questo schema assicura che le risorse vengano sempre ripulite, anche se si verifica un'eccezione all'interno del blocco!
Provalo tu
using System;
using DataAccess;
class Program
{
public static void Main(string[] args)
{
string connectionName = Console.ReadLine();
string sqlQuery = Console.ReadLine();
// TODO: Usa un'istruzione 'using' per creare una DatabaseConnection
// All'interno del blocco using:
// 1. Chiama il metodo Query con sqlQuery
// 2. Stampa il risultato del metodo Query
// Il metodo Dispose verrà chiamato automaticamente al termine del blocco using
}
}
Questa lezione include un breve quiz. Inizia la lezione per rispondere e tenere traccia dei tuoi progressi.
Tutte le lezioni di Programmazione orientata agli oggetti
1Fondamenti della programmazione orientata agli oggetti
File esterniNamespace e direttiveIntroduzione a classi e oggettiLa parola chiave "this"Metodi e parametriCampi e proprietàCostruttoriInizializzatori di oggettiRiepilogo - Calcolatrice semplice4Ereditarietà
Sintassi di base dell'ereditarietà (:)La parola chiave 'base'Parole chiave virtual e overrideClassi sealedLa classe base 'object'Riepilogo - Gerarchia dei dipendenti7Funzionalità avanzate
Sovraccarico degli operatoriIndicizzatori (this[])Override di ToString()Metodi di estensioneRiepilogo - Lista personalizzata10Pattern di progettazione Parte 1
Introduzione ai pattern di progettazioneSingleton thread-safePattern FactoryPattern Observer (eventi)Pattern Strategy2Proprietà e membri statici
Proprietà implementate automaticamenteProprietà di sola lettura e di sola scritturaCampi e metodi staticiClassi staticheMembri con corpo di espressione5Polimorfismo e interfacce
Polimorfismo a compile time e runtimeInterfaccia o classe astrattaInterfacce multipleInterfacce espliciteUpcasting e downcastingRipasso: calcolatore di forme8Concetti avanzati di programmazione a oggetti
Composizione invece dell'ereditarietàTipi generici (classi e metodi)Delegati ed eventiAttributi e reflectionIDisposable e istruzione usingNozioni di base sull'iniezione delle dipendenze11Pattern di progettazione, parte 2
Pattern del ComandoPattern dell’AdattatorePattern del DecoratorePattern Template MethodPattern dello StatoPattern Composito3Architettura delle classi
Dati di istanza vs staticiParole chiave 'readonly' e 'const'Campi di supportoRiepilogo - Gestore di conti bancari6Incapsulamento
Modificatori di accessoProprietà per l'incapsulamentoImplementazione dell'occultamento dei datiModelli di immutabilitàRiepilogo - Registri degli studentiEsercitati da solo: Compilatore C# online