.NET Framework
Uitzonderingen
Zoeken…
Opmerkingen
Verwant:
Een uitzondering vangen
Code kan en moet uitzonderingen maken in uitzonderlijke omstandigheden. Voorbeelden hiervan zijn:
- Poging om voorbij het einde van een stream te lezen
- Geen vereiste machtigingen voor toegang tot een bestand
- Poging om een ongeldige bewerking uit te voeren, zoals delen door nul
- Een time-out bij het downloaden van een bestand van internet
De beller kan met deze uitzonderingen omgaan door ze te "vangen" en moet dit alleen doen wanneer:
- Het kan de uitzonderlijke omstandigheid oplossen of op de juiste manier herstellen, of;
- Het kan een extra context bieden voor de uitzondering die nuttig zou zijn als de uitzondering opnieuw moet worden gegenereerd (uitzonderingen worden opnieuw opgevangen door uitzonderingsbehandelaars verderop in de oproepstack)
Opgemerkt dient te worden dat de keuze niet om een uitzondering te vangen is volkomen geldig als het de bedoeling is om het op een hoger niveau worden behandeld.
Het vangen van een uitzondering wordt gedaan door de potentieel gooiende code als volgt in een try { ... }
-blok te wikkelen en de uitzonderingen te vangen die het kan verwerken in een catch (ExceptionType) { ... }
-blok:
Console.Write("Please enter a filename: ");
string filename = Console.ReadLine();
Stream fileStream;
try
{
fileStream = File.Open(filename);
}
catch (FileNotFoundException)
{
Console.WriteLine("File '{0}' could not be found.", filename);
}
Eindelijk een blok gebruiken
Het finally { ... }
blok van een try-finally
of try-catch-finally
zal altijd worden uitgevoerd, ongeacht of er een uitzondering is opgetreden of niet (behalve wanneer een StackOverflowException
is gegenereerd of een aanroep is gedaan naar Environment.FailFast()
).
Het kan worden gebruikt om bronnen die zijn verkregen in het try { ... }
-blok veilig vrij te maken of op te ruimen.
Console.Write("Please enter a filename: ");
string filename = Console.ReadLine();
Stream fileStream = null;
try
{
fileStream = File.Open(filename);
}
catch (FileNotFoundException)
{
Console.WriteLine("File '{0}' could not be found.", filename);
}
finally
{
if (fileStream != null)
{
fileStream.Dispose();
}
}
Gevangen uitzonderingen vangen en opnieuw werpen
Wanneer u een uitzondering wilt opvangen en iets wilt doen, maar u vanwege de uitzondering niet door kunt gaan met de uitvoering van het huidige codeblok, wilt u de uitzondering mogelijk doorsturen naar de volgende uitzonderingshandler in de call-stack. Er zijn goede manieren en slechte manieren om dit te doen.
private static void AskTheUltimateQuestion()
{
try
{
var x = 42;
var y = x / (x - x); // will throw a DivideByZeroException
// IMPORTANT NOTE: the error in following string format IS intentional
// and exists to throw an exception to the FormatException catch, below
Console.WriteLine("The secret to life, the universe, and everything is {1}", y);
}
catch (DivideByZeroException)
{
// we do not need a reference to the exception
Console.WriteLine("Dividing by zero would destroy the universe.");
// do this to preserve the stack trace:
throw;
}
catch (FormatException ex)
{
// only do this if you need to change the type of the Exception to be thrown
// and wrap the inner Exception
// remember that the stack trace of the outer Exception will point to the
// next line
// you'll need to examine the InnerException property to get the stack trace
// to the line that actually started the problem
throw new InvalidOperationException("Watch your format string indexes.", ex);
}
catch (Exception ex)
{
Console.WriteLine("Something else horrible happened. The exception: " + ex.Message);
// do not do this, because the stack trace will be changed to point to
// this location instead of the location where the exception
// was originally thrown:
throw ex;
}
}
static void Main()
{
try
{
AskTheUltimateQuestion();
}
catch
{
// choose this kind of catch if you don't need any information about
// the exception that was caught
// this block "eats" all exceptions instead of rethrowing them
}
}
U kunt filteren op uitzonderingstype en zelfs op uitzonderingseigenschappen (nieuw in C # 6.0, iets langer beschikbaar in VB.NET (nodig citaat)):
Documentatie / C # / nieuwe functies
Uitzonderingsfilters
Omdat C # 6.0-uitzonderingen kunnen worden gefilterd met de operator when
.
Dit is vergelijkbaar met het gebruik van een eenvoudige if
maar rolt de stapel niet af als niet aan de voorwaarde in het when
wordt voldaan.
Voorbeeld
try
{
// ...
}
catch (Exception e) when (e.InnerException != null) // Any condition can go in here.
{
// ...
}
Dezelfde info vindt u hier in de C # 6.0-functies : Uitzonderingsfilters
Een uitzondering opnieuw uitwerken binnen een vangblok
Binnen een catch
blok kan het throw
trefwoord op zichzelf worden gebruikt, zonder een uitzonderingswaarde op te geven, om de uitzondering te vangen die zojuist is gevangen. Door een uitzondering opnieuw te verwerken, kan de oorspronkelijke uitzondering doorgaan in de afhandelingsketen voor uitzonderingen, waarbij de oproepstack of bijbehorende gegevens behouden blijven:
try {...}
catch (Exception ex) {
// Note: the ex variable is *not* used
throw;
}
Een veel voorkomend antipatroon is om in plaats daarvan throw ex
te throw ex
, wat tot gevolg heeft dat de weergave van de volgende uitzonderingshandler op de stacktracering wordt beperkt:
try {...}
catch (Exception ex) {
// Note: the ex variable is thrown
// future stack traces of the exception will not see prior calls
throw ex;
}
Over het algemeen is het gebruik van throw ex
niet wenselijk, aangezien toekomstige uitzonderingshandlers die de stack-trace inspecteren, alleen oproepen kunnen zien die teruggaan tot throw ex
. Door de ex
variabele weg te laten en alleen het sleutelwoord throw
gebruiken, wordt de oorspronkelijke uitzondering "opgedroogd" .
Een uitzondering maken van een andere methode met behoud van de informatie
Af en toe wil je een uitzondering vangen en deze uit een andere thread of methode gooien met behoud van de oorspronkelijke uitzonderingsstapel. Dit kan worden gedaan met ExceptionDispatchInfo
:
using System.Runtime.ExceptionServices;
void Main()
{
ExceptionDispatchInfo capturedException = null;
try
{
throw new Exception();
}
catch (Exception ex)
{
capturedException = ExceptionDispatchInfo.Capture(ex);
}
Foo(capturedException);
}
void Foo(ExceptionDispatchInfo exceptionDispatchInfo)
{
// Do stuff
if (capturedException != null)
{
// Exception stack trace will show it was thrown from Main() and not from Foo()
exceptionDispatchInfo.Throw();
}
}