Afhandeling van uitzonderingen (C#-programmeerhandleiding)
Een try-blok wordt door C#-programmeurs gebruikt om code te partitioneren die mogelijk wordt beïnvloed door een uitzondering. Gekoppelde catch-blokken worden gebruikt om eventuele resulterende uitzonderingen af te handelen. Een definitief blok bevat code die wordt uitgevoerd of er al dan niet een uitzondering wordt gegenereerd in het try
blok, zoals het vrijgeven van resources die in het try
blok zijn toegewezen. Een try
blok vereist een of meer gekoppelde catch
blokken, of een finally
blok, of beide.
In de volgende voorbeelden ziet u een try-catch
instructie, een try-finally
instructie en een try-catch-finally
instructie.
try
{
// Code to try goes here.
}
catch (SomeSpecificException ex)
{
// Code to handle the exception goes here.
// Only catch exceptions that you know how to handle.
// Never catch base class System.Exception without
// rethrowing it at the end of the catch block.
}
try
{
// Code to try goes here.
}
finally
{
// Code to execute after the try block goes here.
}
try
{
// Code to try goes here.
}
catch (SomeSpecificException ex)
{
// Code to handle the exception goes here.
}
finally
{
// Code to execute after the try (and possibly catch) blocks
// goes here.
}
Een try
blok zonder of catch
finally
blok veroorzaakt een compilerfout.
Catch Blocks
Een catch
blok kan het type uitzondering opgeven dat moet worden onderschept. De typespecificatie wordt een uitzonderingsfilter genoemd. Het uitzonderingstype moet worden afgeleid van Exception. Geef in het algemeen niet op Exception als uitzonderingsfilter, tenzij u weet hoe u alle uitzonderingen moet verwerken die in het try
blok kunnen worden gegenereerd, of als u een throw
instructie aan het einde van het catch
blok hebt opgenomen.
Meerdere catch
blokken met verschillende uitzonderingsklassen kunnen aan elkaar worden gekoppeld. De catch
blokken worden van boven naar beneden geëvalueerd in uw code, maar er wordt slechts één catch
blok uitgevoerd voor elke uitzondering die wordt gegenereerd. Het eerste catch
blok dat het exacte type of een basisklasse van de gegenereerde uitzondering aangeeft, wordt uitgevoerd. Als er geen catch
blok een overeenkomende uitzonderingsklasse aangeeft, wordt er een catch
blok geselecteerd waarvoor geen type is geselecteerd, als deze aanwezig is in de instructie. Het is belangrijk om blokken te positioneren catch
met de meest specifieke (dat wil gezegd, de meest afgeleide) uitzonderingsklassen eerst.
Uitzonderingen vangen wanneer aan de volgende voorwaarden wordt voldaan:
- U hebt een goed begrip van de reden waarom de uitzondering kan worden gegenereerd en u kunt een specifiek herstel implementeren, zoals het vragen van de gebruiker om een nieuwe bestandsnaam in te voeren wanneer u een FileNotFoundException object ondervangt.
- U kunt een nieuwe, specifiekere uitzondering maken en genereren.
int GetInt(int[] array, int index) { try { return array[index]; } catch (IndexOutOfRangeException e) { throw new ArgumentOutOfRangeException( "Parameter index is out of range.", e); } }
- U wilt een uitzondering gedeeltelijk afhandelen voordat u deze doorgeeft voor meer verwerking. In het volgende voorbeeld wordt een
catch
blok gebruikt om een vermelding toe te voegen aan een foutenlogboek voordat de uitzondering opnieuw wordt beperkt.try { // Try to access a resource. } catch (UnauthorizedAccessException e) { // Call a custom error logging procedure. LogError(e); // Re-throw the error. throw; }
U kunt ook uitzonderingsfilters opgeven om een Booleaanse expressie toe te voegen aan een catch-component. Uitzonderingsfilters geven aan dat een specifieke catch-component alleen overeenkomt wanneer aan die voorwaarde wordt voldaan. In het volgende voorbeeld gebruiken beide catch-componenten dezelfde uitzonderingsklasse, maar er wordt een extra voorwaarde gecontroleerd om een ander foutbericht te maken:
int GetInt(int[] array, int index)
{
try
{
return array[index];
}
catch (IndexOutOfRangeException e) when (index < 0)
{
throw new ArgumentOutOfRangeException(
"Parameter index cannot be negative.", e);
}
catch (IndexOutOfRangeException e)
{
throw new ArgumentOutOfRangeException(
"Parameter index cannot be greater than the array size.", e);
}
}
Een uitzonderingsfilter false
dat altijd wordt geretourneerd, kan worden gebruikt om alle uitzonderingen te onderzoeken, maar ze niet te verwerken. Een typisch gebruik is het vastleggen van uitzonderingen:
public class ExceptionFilter
{
public static void Main()
{
try
{
string? s = null;
Console.WriteLine(s.Length);
}
catch (Exception e) when (LogException(e))
{
}
Console.WriteLine("Exception must have been handled");
}
private static bool LogException(Exception e)
{
Console.WriteLine($"\tIn the log routine. Caught {e.GetType()}");
Console.WriteLine($"\tMessage: {e.Message}");
return false;
}
}
De LogException
methode retourneert altijd, geen catch
component die gebruikmaakt van dit uitzonderingsfilterfalse
. De catch-component kan algemeen zijn, met behulp van System.Exceptionen latere componenten kunnen specifiekere uitzonderingsklassen verwerken.
Ten slotte blokken
Met een finally
blok kunt u acties opschonen die in een try
blok worden uitgevoerd. Indien aanwezig, wordt het finally
blok als laatste uitgevoerd, na het try
blok en een overeenkomend catch
blok. Er finally
wordt altijd een blok uitgevoerd, ongeacht of er een uitzondering wordt gegenereerd of een catch
blok dat overeenkomt met het uitzonderingstype wordt gevonden.
Het finally
blok kan worden gebruikt om resources, zoals bestandsstromen, databaseverbindingen en grafische ingangen, vrij te geven zonder te wachten tot de garbagecollector in de runtime de objecten heeft voltooid.
In het volgende voorbeeld wordt het finally
blok gebruikt om een bestand te sluiten dat in het try
blok wordt geopend. U ziet dat de status van de bestandsgreep is gecontroleerd voordat het bestand wordt gesloten. Als het blok het try
bestand niet kan openen, heeft de bestandsgreep nog steeds de waarde null
en probeert het blok het finally
niet te sluiten. Als het bestand in plaats daarvan is geopend in het try
blok, wordt het finally
geopende bestand gesloten.
FileStream? file = null;
FileInfo fileinfo = new System.IO.FileInfo("./file.txt");
try
{
file = fileinfo.OpenWrite();
file.WriteByte(0xF);
}
finally
{
// Check for null because OpenWrite might have failed.
file?.Close();
}
C#-taalspecificatie
Zie Uitzonderingen en de instructie Try in de C#-taalspecificatie voor meer informatie. De taalspecificatie is de definitieve bron voor de C#-syntaxis en het gebruik.