This article has been localized into Dutch by the community.
Exception afhandeling
In elke programma gaan er dingen soms fout. Bij C# zijn we gezegend met een goede compiler die ons helpt om de meeste fouten te voorkomen. Het is echter duidelijk dat hij niet elke fout die voorkomt kan zien. In die gevallen komt het .NET framework met een 'exception' om ons te laten weten dat er iets fout ging. In een eerder hoofdstuk over arrays beschreef ik hoe we een exception zouden krijgen als we teveel items in een array zouden proppen. Hier komt een voorbeeld:
using System;
using System.Collections;
namespace ConsoleApplication1
{
class Program
{
static void Main(string[] args)
{
int[] numbers = new int[2];
numbers[0] = 23;
numbers[1] = 32;
numbers[2] = 42;
foreach(int i in numbers)
Console.WriteLine(i);
Console.ReadLine();
}
}
}
Okee, probeer dit voorbeeld uit te voeren en je zult zien waar ik het over heb. Zie je wat we verkeerd doen? We hebben een array gedefinieerd met ruimte voor 2 items, en toch proberen we er 3 ruimtes in te gebruiken. Uiteraard leidt dit tot een 'error', zoals je kunt zien als je dit programma probeert uit te voeren. Als het uitvoert binnen Visual Studio dan geeft de IDE een paar opties voor de exception, maar als je het programma probeert uit te voeren door te dubbelklikken op de EXE file, dan krijg je een gemene 'error'. Als je weet wat er speelt, kun je er wat aan doen. Hier is een lichtelijk gewijzigde versie van bovenstaande code:
int[] numbers = new int[2];
try
{
numbers[0] = 23;
numbers[1] = 32;
numbers[2] = 42;
foreach(int i in numbers)
Console.WriteLine(i);
}
catch
{
Console.WriteLine("Something went wrong!");
}
Console.ReadLine();
Laat ik je voorstellen aan je nieuwe beste vriend als het aankomt op error 'handling': het try..catch block. Probeer het programma nu te runnen en zie het verschil. In plaats van dat Visual Studio/Windows ons vertelt dat er een ernstig probleem is opgetreden, moeten we nu ons eigen verhaal vertellen. Maar zou het niet aardig zijn als we konden zeggen wat er precies fout ging? Geen probleem:
catch(Exception ex)
{
Console.WriteLine("An error occured: " + ex.Message);
}
Zoals je kunt zien, hebben we iets toegevoegd aan het catch statement. We zeggen nu welke exception we willen pakken, in dit geval de basis van alle exceptions, de Exception. Hierdoor krijgen enige info over het probleem dat de exception veroorzaakte, en door de Message property af te drukken, krijgen we een begrijpelijke beschrijving van het probleem.
Zoals ik zei, is Exception het meest algemene type exception. De regels van het afhandelen van exceptions zeggen ons dat we altijd de minst algemene moeten gebruiken, en in dit geval weten we het exacte type exception dat door onze code wordt voortgebracht. Hoe? Omdat Visual Studio dat zei toen we er niks aan deden. Als je twijfelt, geeft de documentatie doorgaans een beschrijving welke exception(s) een method opwerpt. Een andere manier om er achter te komen is om de Exception class te gebruiken om ons het te vertellen. Verander de output regel op deze manier:
Console.WriteLine("An error occured: " + ex.GetType().ToString());
Het resultaat is, zoals verwacht de IndexOutOfRangeException. We zouden hiervoor deze exception moeten afhandelen, maar er staat ons niets in de weg om meer dan één exception af te handelen. In sommige situaties zou je allerlei dingen willen doen, afhankelijk van welke exception werd opgeworpen. Verander ons catch block op de volgende manier:
catch(IndexOutOfRangeException ex)
{
Console.WriteLine("An index was out of range!");
}
catch(Exception ex)
{
Console.WriteLine("Some sort of error occured: " + ex.Message);
}
Zoals je ziet kijken we eerst naar de IndexOutOfRangeException. Als we dat anders zouden doen, zou het catch block met de Exception class hem krijgen, omdat alle exceptions ervan zijn afgeleid. Dus met andere woorden, je moet de meeste specifieke exceptions het eerst gebruiken.
Nog iets wat je zou moeten weten over zorgelijke exceptions, is het finally block. Het finally block kan worden toegevoegd aan een set van catch blocks, of los gebruikt worden, afhankelijk van wat je nodig hebt. De code binnen een finally block wordt altijd uitgevoerd, exception of geen exception. Het is een goed ding voor als je file referenties wil sluiten, of objecten verwijderen als je ze niet langer nodig hebt. Omdat onze voorbeelden tot hier toe behoorlijk eenvoudig zijn, hebben we enige schoonmaak niet nodig gehad, omdat de garbage collector dat doet. Maar omdat het toch zo is dat we soms het finally block nodig hebben, is hier een uitgebreide versie van ons voorbeeld:
int[] numbers = new int[2];
try
{
numbers[0] = 23;
numbers[1] = 32;
numbers[2] = 42;
foreach(int i in numbers)
Console.WriteLine(i);
}
catch(IndexOutOfRangeException ex)
{
Console.WriteLine("An index was out of range!");
}
catch(Exception ex)
{
Console.WriteLine("Some sort of error occured: " + ex.Message);
}
finally
{
Console.WriteLine("It's the end of our try block. Time to clean up!");
}
Console.ReadLine();
Als je de code runt, zie je dat zowel het eerste exception block als het finally block worden uitgevoerd. Als je de regel verwijdert die het getal 42 toevoegt aan de array, zie je dat alleen het finally block wordt bereikt.
Een ander belangrijk ding dat je moet weten over exceptions is, hoe ze impact hebben op de method waarin de exception optreedt. Niet alle onafgehandelde exceptions zijn fataal voor je applicatie, maar als ze dat niet zijn, mag je niet verwachten dat de resterende code van de method zal worden uitgevoerd. Als je echter de exception wel afhandelt, worden alleen de regels na het try block uitgevoerd. In ons voorbeeld wordt de lus die de waarden van de array geeft nooit bereikt, omdat het try block direct naar de catch/finally blocks gaat als de exceptie wordt opgeworpen. Maar toch wordt de laatste regel bereikt, waarin we van de console kunnen lezen dat we moeten voorkomen dat de applicatie er onmiddellijk mee stopt. je zult hier altijd aan moeten denken als je try blocks construeert.