8Exceptions
#Standaard exceptions: welke wanneer
| Exception | Gebruik bij |
|---|---|
ArgumentException | ongeldig argument (leeg id, einddatum vóór begindatum) |
ArgumentNullException | argument is null |
ArgumentOutOfRangeException | getal buiten bereik (accu 0..100, negatieve leeftijd) |
InvalidOperationException | actie past niet bij de toestand (auto starten die al rijdt) |
KeyNotFoundException | sleutel niet in dictionary |
NullReferenceException | (gooi je zelf nooit) iets was null |
FileNotFoundException | bestand ontbreekt |
FormatException | tekst is geen geldig getal (double.Parse) |
| Eigen exception | domeinregel geschonden (voertuig niet beschikbaar, saldo onvoldoende) |
#Gooien (throw)
public Student(string naam, int leeftijd) { ArgumentException.ThrowIfNullOrWhiteSpace(naam); if (leeftijd < 16 || leeftijd > 120) throw new ArgumentOutOfRangeException(nameof(leeftijd), leeftijd, "Leeftijd moet tussen 16 en 120 liggen."); Naam = naam; Leeftijd = leeftijd; }
Uitleg
Controleer argumenten aan het begin van een constructor of methode en gooi meteen een passende exception. Zo kan een object nooit in een ongeldige toestand bestaan. nameof zet de parameternaam in de foutmelding zonder dat je hem als tekst hoeft te typen.
nameof- Geeft de naam van een variabele of parameter als tekst, en blijft kloppen als je hem hernoemt.
throw- Gooit een exception; de methode stopt direct en de fout gaat omhoog naar de aanroeper.
ArgumentOutOfRangeException- Voor een waarde buiten het toegestane bereik.
ThrowIfNullOrWhiteSpace- Gooit een exception als de tekst null, leeg of alleen spaties is (.NET 8+).
#Custom exception (sjabloon)
public class VoertuigNietBeschikbaarException : Exception { public string VoertuigId { get; } public VoertuigNietBeschikbaarException(string voertuigId, string melding) : base(melding) // melding → ex.Message { VoertuigId = voertuigId; } // optioneel: met inner exception public VoertuigNietBeschikbaarException(string melding, Exception inner) : base(melding, inner) { VoertuigId = ""; } }
Uitleg
Een eigen exception erft van Exception en geeft de melding door met : base(melding), zodat ex.Message werkt. Extra properties (zoals het voertuig-id) geven de aanroeper context. De tweede constructor bewaart een onderliggende fout als inner exception.
base(...)- Roept de constructor van de ouderklasse aan, vóór de eigen constructor draait.
: Exception- Eigen exception-klasse; erft alles van de standaard
Exception. { get; }- Alleen-lezen property; de waarde wordt in de constructor gezet.
Hiërarchie: BigBrutusException : Exception, en ApparaatOfflineException : BigBrutusException enz. Dan kun je met één catch (BigBrutusException) alles van je domein vangen.
#Vangen: try / catch / finally
StreamReader? reader = null; try { reader = new StreamReader("cijfers.txt"); string regel = reader.ReadLine()!; Console.WriteLine($"Eerste cijfer: {double.Parse(regel)}"); } catch (FileNotFoundException ex) // specifiek EERST { Console.WriteLine($"Niet gevonden: {ex.FileName}"); } catch (FormatException) // variabele mag weg { Console.WriteLine("Geen geldig cijfer."); } catch (Exception ex) // algemeen als LAATSTE { Console.WriteLine($"Onverwacht: {ex.Message}"); } finally // draait ALTIJD { reader?.Dispose(); }
Uitleg
try bevat de code die mis kan gaan, de catch-blokken vangen specifieke fouten af (specifiek eerst, algemeen als laatste), en finally draait altijd, ook na een fout. Hier wordt het bestand daar netjes gesloten.
?.- Roept alleen aan als het object niet null is; anders is het resultaat null.
Console.ReadLine- Leest een regel invoer als tekst (kan null zijn).
try / catchtrybevat code die kan falen;catchvangt een specifiek type fout af.finally- Blok dat altijd draait, met of zonder fout; voor opruimen.
Dispose- Geeft een resource (zoals een open bestand) vrij.
StreamReader- Leest een tekstbestand regel voor regel.
$"...{x}"- String-interpolatie: zet de waarde van
xdirect in de tekst.
// using: automatisch Dispose, vervangt finally using var reader = new StreamReader(pad); // when: filter catch (HttpRequestException ex) when (ex.StatusCode == HttpStatusCode.NotFound) // opnieuw gooien met behoud van stacktrace catch (Exception ex) { _log.Fout(ex.Message); throw; } // niet: throw ex;
Uitleg
using var sluit een resource automatisch aan het einde van het blok, dus geen finally nodig. Met when vang je een exception alleen als een extra voorwaarde klopt. Gebruik throw; zonder variabele om opnieuw te gooien met behoud van de originele stacktrace.
throw- Gooit een exception; de methode stopt direct en de fout gaat omhoog naar de aanroeper.
when- Extra voorwaarde bij een
catch: alleen vangen als die klopt. using var- Ruimt de resource automatisch op (Dispose) aan het einde van het blok.
StreamReader- Leest een tekstbestand regel voor regel.
var- De compiler leidt het type zelf af uit de rechterkant.
#Wanneer vangen?
- Vang alleen als je op die plek iets zinnigs kunt doen: herstellen, context toevoegen (opnieuw gooien), of op de buitenste laag (Program/UI) netjes melden.
- Niet vangen om te negeren: een lege
catch { }is een swallowed exception (anti-pattern). - Verwachte gebruikersfouten (geen getal getypt) los je op zonder exception:
int.TryParse. - Log vóór je gooit als een weigering zichtbaar moet zijn in de log, en geef dan de exception door.
#Ontwerpkeuzes
| Situatie | Aanpak |
|---|---|
| Negatieve leeftijd in constructor | ArgumentOutOfRangeException gooien (object mag niet ongeldig bestaan) |
Externe betaal-API faalt (HttpRequestException) | Niet verbergen: op buitenste laag vangen, loggen (Error), evt. retry, nette melding |
| Product niet op voorraad (vraag 10, nog 3) | Eigen domein-exception (bv. OnvoldoendeVoorraadException) met de getallen als properties |
| Einddatum vóór begindatum | ArgumentException in de constructor |
| Auto starten die al rijdt | InvalidOperationException (verkeerde toestand) |
| Gebruiker typt "twintig" i.p.v. een getal | Geen exception: int.TryParse en opnieuw vragen |
Stacktrace lezen: bovenste regel = type + melding. Daaronder at Klasse.Methode() in Bestand.cs:line N: de bovenste regel uit jouw code is meestal de plek van de fout.