Ce face Excepții personalizate
Când nicio excepție din .NET nu descrie bine problema (stoc insuficient, comandă deja plătită), creează o clasă care moștenește Exception. Numele se termină prin convenție în Exception, iar codul care apelează o poate prinde separat cu catch (StocInsuficientException ex).
Pune în excepție datele utile celui care o tratează (produsul, cantitatea cerută) ca proprietăți, nu doar în mesaj. Când transformi o excepție de nivel jos într-una de domeniu, dă-o pe cea originală ca innerException, ca să nu pierzi cauza.
Ghidul .NET recomandă trei constructori: fără parametri, cu mesaj și cu mesaj plus excepție interioară. Constructorul de serializare (SerializationInfo) este învechit din .NET 8 și nu mai trebuie scris.
Exemple
Exemplul 1: Excepție cu date suplimentare
var stoc = new Dictionary<string, int> { ["laptop"] = 2 };
try
{
Comanda(stoc, "laptop", 5);
}
catch (StocInsuficientException ex)
{
Console.WriteLine(ex.Message);
Console.WriteLine($"Disponibil: {ex.Disponibil}");
}
static void Comanda(Dictionary<string, int> stoc, string produs, int cantitate)
{
int disponibil = stoc.GetValueOrDefault(produs);
if (cantitate > disponibil)
throw new StocInsuficientException(produs, cantitate, disponibil);
stoc[produs] = disponibil - cantitate;
}
class StocInsuficientException(string produs, int cerut, int disponibil)
: Exception($"Stoc insuficient pentru {produs}: cerut {cerut}, disponibil {disponibil}.")
{
public string Produs { get; } = produs;
public int Disponibil { get; } = disponibil;
}
Rezultat
Stoc insuficient pentru laptop: cerut 5, disponibil 2.
Disponibil: 2
Exemplul 2: Excepție interioară (InnerException)
Eroarea de format devine o excepție de domeniu, dar cauza rămâne disponibilă în InnerException.
try
{
CitesteConfig("port=abc");
}
catch (ConfigException ex)
{
Console.WriteLine(ex.Message);
Console.WriteLine(ex.InnerException?.GetType().Name);
}
static int CitesteConfig(string linie)
{
try
{
return int.Parse(linie.Split('=')[1]);
}
catch (FormatException ex)
{
throw new ConfigException($"Valoare invalidă în '{linie}'", ex);
}
}
class ConfigException : Exception
{
public ConfigException() { }
public ConfigException(string message) : base(message) { }
public ConfigException(string message, Exception inner) : base(message, inner) { }
}
Rezultat
Valoare invalidă în 'port=abc'
FormatException
Greșeli frecvente
- Moștenirea din
ApplicationException: nu aduce nimic în plus, ghidurile .NET recomandă directException. - Aruncarea unei excepții noi fără
innerExceptionpierde cauza reală a erorii. - Câte o clasă de excepție pentru fiecare mesaj posibil. Creează o excepție nouă doar dacă cineva o va prinde separat.
Comenzi înrudite
throw și throw expressions: 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.try / finally: Blocul finally rulează mereu la ieșirea din try: după succes, după o excepție prinsă sau neprinsă și după return.Moștenire: virtual, override și base: O clasă derivată preia membrii clasei de bază (class B : A); metodele virtual pot fi înlocuite cu override, iar base apelează varianta de bază.