Ce face try / catch și using (IDisposable)
Blocul try / catch / finally interceptează erorile apărute la rulare (excepții derivate din System.Exception) și permite tratarea lor diferențiată în funcție de tipul excepției și de filtrele condiționale when. Ordinea blocurilor catch trebuie să meargă întotdeauna de la excepția cea mai specifică (de exemplu FileNotFoundException) către cea mai generală (IOException, apoi Exception).
Pentru obiectele care dețin resurse neadministrate de Garbage Collector (fișiere deschise, conexiuni la baza de date SqlConnection / NpgsqlConnection, fluxuri Stream, semne de anulare CancellationTokenSource) și care implementează interfața IDisposable (sau IAsyncDisposable), declarația modernă using var x = ...; (introdusă în C# 8) garantează apelarea automată a metodei x.Dispose() (într-un bloc finally generat de compilator) la ieșirea din metoda curentă, chiar dacă apare o excepție pe parcurs.
Parametri, metode și opțiuni
| Parametru / Metodă | Descriere |
|---|---|
try { ... } catch (Ex ex) { ... } |
Execută codul din try și transferă controlul în blocul catch corespunzător dacă este aruncată o excepție. |
catch (Ex ex) when (conditie) |
Filtru de excepție (C# 6+): intră în blocul catch doar dacă expresia conditie este true, fără a altera stack trace-ul. |
throw; vs. throw ex; |
Instrucțiunea throw; simplă re-aruncă excepția păstrând stack trace-ul original intact (nu scrie niciodată throw ex;!). |
using var r = new Resursa(); |
Declarație using (C# 8+): eliberează automat resursa (r.Dispose()) la sfârșitul blocului curent. |
await using var r = ...; |
Varianta asincronă pentru resurse IAsyncDisposable (apelează automat await r.DisposeAsync()). |
ArgumentNullException.ThrowIfNull(arg) |
Metodă statică rapidă (.NET 6+) pentru validarea parametrilor la începutul metodelor. |
Exemple
Exemplul 1: Eliberarea deterministă a resurselor cu using var și tratarea specifică a excepțiilor
Demonstrăm ordinea exactă în care using var apelează Dispose() la ieșirea din bloc, chiar și atunci când se aruncă și se prinde o excepție.
try
{
using var conexiune = new ConexiuneSimulata("db-primar.intern");
conexiune.ExecutaInterogare("SELECT * FROM facturi");
conexiune.ExecutaInterogare("EROARE_RETEA");
}
catch (InvalidOperationException ex) when (ex.Message.Contains("RETEA"))
{
Console.WriteLine($"[CATCH] Eroare tranzitorie capturată: {ex.Message}");
}
public sealed class ConexiuneSimulata : IDisposable
{
private readonly string _host;
public ConexiuneSimulata(string host)
{
_host = host;
Console.WriteLine($"[OPEN] Conexiune deschisă către {_host}");
}
public void ExecutaInterogare(string sql)
{
if (sql == "EROARE_RETEA")
throw new InvalidOperationException("EROARE_RETEA: Conexiunea a fost întreruptă.");
Console.WriteLine($"[EXEC] Rulare: {sql}");
}
public void Dispose() => Console.WriteLine($"[DISPOSE] Conexiunea către {_host} a fost închisă garantat.");
}
Ieșire în consolă
[OPEN] Conexiune deschisă către db-primar.intern
[EXEC] Rulare: SELECT * FROM facturi
[DISPOSE] Conexiunea către db-primar.intern a fost închisă garantat.
[CATCH] Eroare tranzitorie capturată: EROARE_RETEA: Conexiunea a fost întreruptă.
Exemplul 2: Clauze guard moderne în .NET 8 (ThrowIfNullOrWhiteSpace și ThrowIfNegativeOrZero)
În .NET 7 și .NET 8, clasele ArgumentException și ArgumentOutOfRangeException expun metode statice ThrowIf... care înlocuiesc blocurile manuale if (...) throw new ....
try
{
CreeazaFactura(" ", -50m);
}
catch (ArgumentException ex)
{
Console.WriteLine($"Validare eșuată ({ex.GetType().Name}): {ex.Message}");
}
static void CreeazaFactura(string client, decimal suma)
{
ArgumentException.ThrowIfNullOrWhiteSpace(client);
ArgumentOutOfRangeException.ThrowIfNegativeOrZero(suma);
}
Ieșire în consolă
Validare eșuată (ArgumentException): The value cannot be an empty string or composed entirely of whitespace. (Parameter 'client')
Greșeli frecvente
- Scrierea
catch (Exception ex) { Log(ex); throw ex; }— instrucțiuneathrow ex;resetează stiva de apeluri (StackTrace) la linia luithrow ex;, ștergând linia reală unde a apărut bug-ul! Scrie întotdeaunathrow;fără variabilă pentru a păstra stack trace-ul original. - Folosirea unor blocuri
catch (Exception) { }goale care „înghit” silențios orice eroare, făcând depanarea imposibilă. - Uitarea lui
usingla crearea obiectelorFileStream,StreamReadersau conexiunilor DB, ceea ce lasă fișierele blocate pe disc până la rularea imprevizibilă a Garbage Collector-ului.
Funcții și concepte înrudite
File.ReadAllText / WriteAllTextAsync: Citește și scrie fișiere text sau linii pe disc (sincron și asincron) și construiește căi multi-platformă cu Path.Combine.async / await și Task<T>: Execută operațiuni I/O neblocante (rețea, baze de date, fișiere) și coordonează sarcini concurente cu Task și Task.WhenAll.HttpClient (GetFromJsonAsync): Trimite cereri HTTP asincrone către API-uri REST și deserializează direct răspunsurile JSON cu metodele din System.Net.Http.Json.