throw și throw expressions în C# (.NET)

OOP modern și programare asincronă C# 1.0 (throw expression: C# 7.0)

Aruncă o excepție care oprește execuția normală; throw; simplu re-aruncă excepția prinsă, păstrând locul unde a apărut.

Sintaxă C#
throw new ArgumentException("mesaj", nameof(param));   throw;   x ?? throw new ...

Ce face throw și throw expressions

throw urmat de un obiect excepție întrerupe metoda curentă și urcă pe stiva de apeluri până la primul catch potrivit. Dacă nu există niciunul, programul se oprește. Alege tipul care descrie problema: ArgumentException / ArgumentNullException / ArgumentOutOfRangeException pentru argumente greșite, InvalidOperationException când obiectul nu e în starea potrivită.

Într-un catch, throw; fără argument re-aruncă aceeași excepție cu stiva originală. throw ex; repornește stiva din acel punct și pierzi locul real al erorii.

Din C# 7, throw poate apărea și ca expresie: după ??, în operatorul ?: și în corpurile cu săgeată. Din .NET 8 există și metode de verificare gata făcute, de exemplu ArgumentOutOfRangeException.ThrowIfNegative(suma).

Exemple

Exemplul 1: Validare cu throw și throw expression

Mesajul lui ArgumentException include automat numele parametrului.

try
{
    Retrage(sold: 100, suma: 250);
}
catch (InvalidOperationException ex)
{
    Console.WriteLine(ex.Message);
}

try
{
    Retrage(sold: 100, suma: -5);
}
catch (ArgumentException ex)
{
    Console.WriteLine(ex.Message);
}

string? oras = null;
try
{
    string sigur = oras ?? throw new ArgumentNullException(nameof(oras));
}
catch (ArgumentNullException ex)
{
    Console.WriteLine(ex.ParamName);
}

static int Retrage(int sold, int suma)
{
    if (suma <= 0)
        throw new ArgumentException("Suma trebuie să fie pozitivă.", nameof(suma));
    if (suma > sold)
        throw new InvalidOperationException("Fonduri insuficiente.");
    return sold - suma;
}

Rezultat

Fonduri insuficiente.
Suma trebuie să fie pozitivă. (Parameter 'suma')
oras

Exemplul 2: Re-aruncare cu throw; după jurnalizare

try
{
    Proceseaza();
}
catch (Exception ex)
{
    Console.WriteLine($"Prinsă sus: {ex.GetType().Name}");
}

static void Proceseaza()
{
    try
    {
        int[] note = [9, 10];
        Console.WriteLine(note[5]);
    }
    catch (IndexOutOfRangeException)
    {
        Console.WriteLine("Jurnal: indice greșit");
        throw;
    }
}

Rezultat

Jurnal: indice greșit
Prinsă sus: IndexOutOfRangeException

Greșeli frecvente

  • throw ex; în loc de throw; șterge stiva originală și face depanarea mult mai grea.
  • Aruncarea lui Exception generic îi obligă pe cei care apelează să prindă tot. Folosește un tip specific sau o excepție proprie.
  • Excepțiile pentru situații normale (de exemplu „produsul nu există”) încetinesc codul și îl fac greu de urmărit. Pentru ele returnează null, bool sau un rezultat.

Comenzi înrudite

  • Excepții personalizate: O clasă proprie derivată din Exception descrie o eroare din domeniul aplicației și poate transporta date suplimentare.
  • try / finally: Blocul finally rulează mereu la ieșirea din try: după succes, după o excepție prinsă sau neprinsă și după return.