C# Language
Behandeling van uitzonderingen
Zoeken…
Basisafhandeling van uitzonderingen
try
{
/* code that could throw an exception */
}
catch (Exception ex)
{
/* handle the exception */
}
Merk op dat het omgaan met alle uitzonderingen met dezelfde code vaak niet de beste aanpak is.
Dit wordt meestal gebruikt als een interne uitzonderingsafhandelingsroutines mislukken, als laatste redmiddel.
Omgaan met specifieke uitzonderingen
try
{
/* code to open a file */
}
catch (System.IO.FileNotFoundException)
{
/* code to handle the file being not found */
}
catch (System.IO.UnauthorizedAccessException)
{
/* code to handle not being allowed access to the file */
}
catch (System.IO.IOException)
{
/* code to handle IOException or it's descendant other than the previous two */
}
catch (System.Exception)
{
/* code to handle other errors */
}
Zorg ervoor dat uitzonderingen in volgorde worden geëvalueerd en dat overerving wordt toegepast. Je moet dus beginnen met de meest specifieke en eindigen met hun voorouder. Op elk gegeven moment wordt slechts één catch-blok uitgevoerd.
Het uitzonderingsobject gebruiken
Je mag uitzonderingen maken en in je eigen code gooien. Het instantiëren van een uitzondering gebeurt op dezelfde manier als elk ander C # -object.
Exception ex = new Exception();
// constructor with an overload that takes a message string
Exception ex = new Exception("Error message");
U kunt vervolgens het trefwoord throw
gebruiken om de uitzondering te verhogen:
try
{
throw new Exception("Error");
}
catch (Exception ex)
{
Console.Write(ex.Message); // Logs 'Error' to the output window
}
Opmerking: als u een nieuwe uitzondering in een blokkeerblok gooit, moet u ervoor zorgen dat de oorspronkelijke uitzondering wordt doorgegeven als "innerlijke uitzondering", bijvoorbeeld
void DoSomething()
{
int b=1; int c=5;
try
{
var a = 1;
b = a - 1;
c = a / b;
a = a / c;
}
catch (DivideByZeroException dEx) when (b==0)
{
// we're throwing the same kind of exception
throw new DivideByZeroException("Cannot divide by b because it is zero", dEx);
}
catch (DivideByZeroException dEx) when (c==0)
{
// we're throwing the same kind of exception
throw new DivideByZeroException("Cannot divide by c because it is zero", dEx);
}
}
void Main()
{
try
{
DoSomething();
}
catch (Exception ex)
{
// Logs full error information (incl. inner exception)
Console.Write(ex.ToString());
}
}
In dit geval wordt ervan uitgegaan dat de uitzondering niet kan worden afgehandeld, maar wordt enige nuttige informatie aan het bericht toegevoegd (en de oorspronkelijke uitzondering is nog steeds toegankelijk via ex.InnerException
door een buitenste uitzonderingsblok).
Het zal iets laten zien als:
System.DivideByZeroException: kan niet delen door b omdat het nul is ---> System.DivideByZeroException: geprobeerd te delen door nul.
op UserQuery.g__DoSomething0_0 () in C: [...] \ LINQPadQuery.cs: regel 36
--- Einde van innerlijke uitzonderingsstapeltrace ---
op UserQuery.g__DoSomething0_0 () in C: [...] \ LINQPadQuery.cs: regel 42
bij UserQuery.Main () in C: [...] \ LINQPadQuery.cs: regel 55
Als je dit voorbeeld in LinqPad probeert, zul je merken dat de regelnummers niet erg zinvol zijn (ze helpen je niet altijd). Maar het doorgeven van een nuttige fouttekst, zoals hierboven gesuggereerd, vermindert vaak de tijd om de locatie van de fout op te sporen, wat in dit voorbeeld duidelijk de lijn is
c = a / b;
in functie DoSomething()
.
Eindelijk blok
try
{
/* code that could throw an exception */
}
catch (Exception)
{
/* handle the exception */
}
finally
{
/* Code that will be executed, regardless if an exception was thrown / caught or not */
}
Het try / catch / finally
blok kan erg handig zijn bij het lezen van bestanden.
Bijvoorbeeld:
FileStream f = null;
try
{
f = File.OpenRead("file.txt");
/* process the file here */
}
finally
{
f?.Close(); // f may be null, so use the null conditional operator.
}
Een blok try moet worden gevolgd door ofwel een catch
of een finally
blok. Aangezien er echter geen catch-blok is, zal de uitvoering de beëindiging veroorzaken. Voor beëindiging worden de instructies in het slotblok uitgevoerd.
Bij het lezen van bestanden hadden we een using
gebruiken als FileStream
(wat OpenRead
retourneert) IDisposable
.
Zelfs als er een return
statement in try
blok, het finally
zal blok meestal uit te voeren; er zijn een paar gevallen waarin dit niet het geval is:
- Wanneer een StackOverflow optreedt .
-
Environment.FailFast
- Het aanvraagproces wordt gedood, meestal door een externe bron.
Implementeren van IErrorHandler voor WCF Services
De implementatie van IErrorHandler voor WCF-services is een geweldige manier om foutafhandeling en logboekregistratie te centraliseren. De hier getoonde implementatie zou elke onverwerkte uitzondering moeten opvangen die wordt gegenereerd als gevolg van een oproep aan een van uw WCF-services. In dit voorbeeld wordt ook getoond hoe een aangepast object wordt geretourneerd en hoe JSON wordt geretourneerd in plaats van de standaard XML.
Implementeer IErrorHandler:
using System.ServiceModel.Channels;
using System.ServiceModel.Dispatcher;
using System.Runtime.Serialization.Json;
using System.ServiceModel;
using System.ServiceModel.Web;
namespace BehaviorsAndInspectors
{
public class ErrorHandler : IErrorHandler
{
public bool HandleError(Exception ex)
{
// Log exceptions here
return true;
} // end
public void ProvideFault(Exception ex, MessageVersion version, ref Message fault)
{
// Get the outgoing response portion of the current context
var response = WebOperationContext.Current.OutgoingResponse;
// Set the default http status code
response.StatusCode = HttpStatusCode.InternalServerError;
// Add ContentType header that specifies we are using JSON
response.ContentType = new MediaTypeHeaderValue("application/json").ToString();
// Create the fault message that is returned (note the ref parameter) with BaseDataResponseContract
fault = Message.CreateMessage(
version,
string.Empty,
new CustomReturnType { ErrorMessage = "An unhandled exception occurred!" },
new DataContractJsonSerializer(typeof(BaseDataResponseContract), new List<Type> { typeof(BaseDataResponseContract) }));
if (ex.GetType() == typeof(VariousExceptionTypes))
{
// You might want to catch different types of exceptions here and process them differently
}
// Tell WCF to use JSON encoding rather than default XML
var webBodyFormatMessageProperty = new WebBodyFormatMessageProperty(WebContentFormat.Json);
fault.Properties.Add(WebBodyFormatMessageProperty.Name, webBodyFormatMessageProperty);
} // end
} // end class
} // end namespace
In dit voorbeeld koppelen we de handler aan het servicegedrag. U kunt dit ook op dezelfde manier koppelen aan IEndpointBehavior, IContractBehavior of IOperationBehavior.
Hechten aan servicegedrag:
using System;
using System.Collections.ObjectModel;
using System.ServiceModel;
using System.ServiceModel.Channels;
using System.ServiceModel.Configuration;
using System.ServiceModel.Description;
using System.ServiceModel.Dispatcher;
namespace BehaviorsAndInspectors
{
public class ErrorHandlerExtension : BehaviorExtensionElement, IServiceBehavior
{
public override Type BehaviorType
{
get { return GetType(); }
}
protected override object CreateBehavior()
{
return this;
}
private IErrorHandler GetInstance()
{
return new ErrorHandler();
}
void IServiceBehavior.AddBindingParameters(ServiceDescription serviceDescription, ServiceHostBase serviceHostBase, Collection<ServiceEndpoint> endpoints, BindingParameterCollection bindingParameters) { } // end
void IServiceBehavior.ApplyDispatchBehavior(ServiceDescription serviceDescription, ServiceHostBase serviceHostBase)
{
var errorHandlerInstance = GetInstance();
foreach (ChannelDispatcher dispatcher in serviceHostBase.ChannelDispatchers)
{
dispatcher.ErrorHandlers.Add(errorHandlerInstance);
}
}
void IServiceBehavior.Validate(ServiceDescription serviceDescription, ServiceHostBase serviceHostBase) { } // end
} // end class
} // end namespace
Configs in Web.config:
...
<system.serviceModel>
<services>
<service name="WebServices.MyService">
<endpoint binding="webHttpBinding" contract="WebServices.IMyService" />
</service>
</services>
<extensions>
<behaviorExtensions>
<!-- This extension if for the WCF Error Handling-->
<add name="ErrorHandlerBehavior" type="WebServices.BehaviorsAndInspectors.ErrorHandlerExtensionBehavior, WebServices, Version=1.0.0.0, Culture=neutral, PublicKeyToken=null" />
</behaviorExtensions>
</extensions>
<behaviors>
<serviceBehaviors>
<behavior>
<serviceMetadata httpGetEnabled="true"/>
<serviceDebug includeExceptionDetailInFaults="true"/>
<ErrorHandlerBehavior />
</behavior>
</serviceBehaviors>
</behaviors>
....
</system.serviceModel>
...
Hier zijn een paar links die nuttig kunnen zijn over dit onderwerp:
https://msdn.microsoft.com/en-us/library/system.servicemodel.dispatcher.ierrorhandler(v=vs.100).aspx
Andere voorbeelden:
IErrorHandler retourneert verkeerde berichttekst wanneer HTTP-statuscode 401 Ongeautoriseerd is
IErrorHandler lijkt mijn fouten in WCF niet te verwerken ... enig idee?
Hoe een aangepaste WCF-foutafhandelaar een JSON-antwoord met een niet-OK http-code te maken?
Hoe stel je de Content-Type header in voor een HttpClient-verzoek?
Aangepaste uitzonderingen maken
U mag aangepaste uitzonderingen implementeren die net als elke andere uitzondering kunnen worden gegenereerd. Dit is zinvol wanneer u uw uitzonderingen tijdens runtime wilt onderscheiden van andere fouten.
In dit voorbeeld maken we een aangepaste uitzondering voor een duidelijke afhandeling van problemen die de toepassing kan hebben tijdens het parseren van een complexe invoer.
Aangepaste uitzonderingsklasse maken
Om een aangepaste uitzondering te maken, maakt u een subklasse van Exception
:
public class ParserException : Exception
{
public ParserException() :
base("The parsing went wrong and we have no additional information.") { }
}
Aangepaste uitzondering wordt erg handig wanneer u extra informatie aan de catcher wilt geven:
public class ParserException : Exception
{
public ParserException(string fileName, int lineNumber) :
base($"Parser error in {fileName}:{lineNumber}")
{
FileName = fileName;
LineNumber = lineNumber;
}
public string FileName {get; private set;}
public int LineNumber {get; private set;}
}
Wanneer u nu catch(ParserException x)
hebt u extra semantiek om de afhandeling van uitzonderingen te verfijnen.
Aangepaste klassen kunnen de volgende functies implementeren om aanvullende scenario's te ondersteunen.
re-gooien
Tijdens het parseren is de oorspronkelijke uitzondering nog steeds interessant. In dit voorbeeld is het een FormatException
omdat de code probeert een string te ontleden, die naar verwachting een getal zal zijn. In dit geval moet de aangepaste uitzondering de opname van de ' InnerException ' ondersteunen:
//new constructor:
ParserException(string msg, Exception inner) : base(msg, inner) {
}
serialisatie
In sommige gevallen kunnen uw uitzonderingen de grenzen van AppDomain overschrijden. Dit is het geval als uw parser in zijn eigen AppDomain wordt uitgevoerd om hot reloading van nieuwe parserconfiguraties te ondersteunen. In Visual Studio kunt u de Exception
gebruiken om dergelijke code te genereren.
[Serializable]
public class ParserException : Exception
{
// Constructor without arguments allows throwing your exception without
// providing any information, including error message. Should be included
// if your exception is meaningful without any additional details. Should
// set message by calling base constructor (default message is not helpful).
public ParserException()
: base("Parser failure.")
{}
// Constructor with message argument allows overriding default error message.
// Should be included if users can provide more helpful messages than
// generic automatically generated messages.
public ParserException(string message)
: base(message)
{}
// Constructor for serialization support. If your exception contains custom
// properties, read their values here.
protected ParserException(SerializationInfo info, StreamingContext context)
: base(info, context)
{}
}
De ParserException gebruiken
try
{
Process.StartRun(fileName)
}
catch (ParserException ex)
{
Console.WriteLine($"{ex.Message} in ${ex.FileName}:${ex.LineNumber}");
}
catch (PostProcessException x)
{
...
}
U kunt ook aangepaste uitzonderingen gebruiken voor het vangen en inpakken van uitzonderingen. Op deze manier kunnen veel verschillende fouten worden omgezet in een enkel fouttype dat nuttiger is voor de toepassing:
try
{
int foo = int.Parse(token);
}
catch (FormatException ex)
{
//Assuming you added this constructor
throw new ParserException(
$"Failed to read {token} as number.",
FileName,
LineNumber,
ex);
}
Wanneer u uitzonderingen behandelt door uw eigen aangepaste uitzonderingen te verhogen, moet u meestal een verwijzing naar de oorspronkelijke uitzondering opnemen in de eigenschap InnerException
, zoals hierboven weergegeven.
Bezorgdheid over de beveiliging
Als het blootleggen van de reden voor de uitzondering de beveiliging in gevaar kan brengen doordat gebruikers de interne werking van uw toepassing kunnen zien, kan het een slecht idee zijn om de interne uitzondering te omzeilen. Dit kan van toepassing zijn als u een klassenbibliotheek maakt die door anderen wordt gebruikt.
Hier is hoe je een aangepaste uitzondering kunt maken zonder de binnenste uitzondering te verpakken:
try
{
// ...
}
catch (SomeStandardException ex)
{
// ...
throw new MyCustomException(someMessage);
}
Conclusie
Wanneer u een aangepaste uitzondering oproept (met omloop of met een nieuwe onverpakte uitzondering), moet u een uitzondering opwerpen die zinvol is voor de beller. Een gebruiker van een klassenbibliotheek kan bijvoorbeeld niet veel weten over hoe die bibliotheek zijn interne werk doet. De uitzonderingen die worden veroorzaakt door de afhankelijkheden van de klassenbibliotheek, hebben geen betekenis. De gebruiker wil eerder een uitzondering die relevant is voor de manier waarop de klassenbibliotheek die afhankelijkheden op een verkeerde manier gebruikt.
try
{
// ...
}
catch (IOException ex)
{
// ...
throw new StorageServiceException(@"The Storage Service encountered a problem saving
your data. Please consult the inner exception for technical details.
If you are not able to resolve the problem, please call 555-555-1234 for technical
assistance.", ex);
}
Uitzondering anti-patronen
Uitzonderingen slikken
Men moet de uitzondering altijd op de volgende manier opnieuw gooien:
try
{
...
}
catch (Exception ex)
{
...
throw;
}
Het opnieuw gooien van een uitzondering zoals hieronder zal de oorspronkelijke uitzondering verdoezelen en zal het originele stapeltrace verliezen. Men zou dit nooit moeten doen! De stapelspoor voorafgaand aan de vangst en opnieuw gegooid gaat verloren.
try
{
...
}
catch (Exception ex)
{
...
throw ex;
}
Honkbaluitzondering afhandeling
Men moet geen uitzonderingen gebruiken als vervanging voor normale flow control constructies zoals if-then statements en while-lussen. Dit anti-patroon wordt ook wel Baseball Exception Handling genoemd .
Hier is een voorbeeld van het anti-patroon:
try
{
while (AccountManager.HasMoreAccounts())
{
account = AccountManager.GetNextAccount();
if (account.Name == userName)
{
//We found it
throw new AccountFoundException(account);
}
}
}
catch (AccountFoundException found)
{
Console.Write("Here are your account details: " + found.Account.Details.ToString());
}
Hier is een betere manier om het te doen:
Account found = null;
while (AccountManager.HasMoreAccounts() && (found==null))
{
account = AccountManager.GetNextAccount();
if (account.Name == userName)
{
//We found it
found = account;
}
}
Console.Write("Here are your account details: " + found.Details.ToString());
vangen (uitzondering)
Er zijn bijna geen (sommigen zeggen geen!) Redenen om het generieke uitzonderingstype in uw code te vangen. Je zou alleen de uitzonderingen moeten vangen die je verwacht, omdat je anders bugs in je code verbergt.
try
{
var f = File.Open(myfile);
// do something
}
catch (Exception x)
{
// Assume file not found
Console.Write("Could not open file");
// but maybe the error was a NullReferenceException because of a bug in the file handling code?
}
Beter doen:
try
{
var f = File.Open(myfile);
// do something which should normally not throw exceptions
}
catch (IOException)
{
Console.Write("File not found");
}
// Unfortunatelly, this one does not derive from the above, so declare separatelly
catch (UnauthorizedAccessException)
{
Console.Write("Insufficient rights");
}
Als er een andere uitzondering gebeurt, hebben we de toepassing opzettelijk laten crashen, zodat deze rechtstreeks in de debugger stapt en we het probleem kunnen oplossen. We moeten geen programma verzenden waar andere uitzonderingen dan toch optreden, dus het is geen probleem om een crash te hebben.
Het volgende is ook een slecht voorbeeld, omdat het uitzonderingen gebruikt om een programmeerfout te omzeilen. Daar zijn ze niet voor ontworpen.
public void DoSomething(String s)
{
if (s == null)
throw new ArgumentNullException(nameof(s));
// Implementation goes here
}
try
{
DoSomething(myString);
}
catch(ArgumentNullException x)
{
// if this happens, we have a programming error and we should check
// why myString was null in the first place.
}
Verzamel uitzonderingen / meerdere uitzonderingen van één methode
Wie zegt dat je niet in één methode meerdere uitzonderingen kunt maken. Als je niet gewend bent om met AggregateExceptions te spelen, kun je in de verleiding komen om je eigen datastructuur te maken om veel dingen weer te geven die fout gaan. Er zijn natuurlijk nog een andere datastructuur die geen uitzondering is, idealer, zoals de resultaten van een validatie. Zelfs als je met AggregateExceptions speelt, sta je misschien aan de ontvangende kant en behandel je ze altijd zonder je te realiseren dat ze je kunnen helpen.
Het is heel aannemelijk om een methode uit te voeren en hoewel het een hele fout zal zijn, wil je meerdere dingen benadrukken die fout zijn gegaan in de uitzonderingen die worden gegooid. Als een voorbeeld kan dit gedrag worden gezien met de manier waarop Parallelle methoden werken, een taak die in meerdere threads is onderverdeeld en een willekeurig aantal van hen kan uitzonderingen genereren en dit moet worden gemeld. Hier is een dom voorbeeld van hoe u hiervan kunt profiteren:
public void Run()
{
try
{
this.SillyMethod(1, 2);
}
catch (AggregateException ex)
{
Console.WriteLine(ex.Message);
foreach (Exception innerException in ex.InnerExceptions)
{
Console.WriteLine(innerException.Message);
}
}
}
private void SillyMethod(int input1, int input2)
{
var exceptions = new List<Exception>();
if (input1 == 1)
{
exceptions.Add(new ArgumentException("I do not like ones"));
}
if (input2 == 2)
{
exceptions.Add(new ArgumentException("I do not like twos"));
}
if (exceptions.Any())
{
throw new AggregateException("Funny stuff happended during execution", exceptions);
}
}
Nesten van uitzonderingen en probeer blokken te vangen.
Men is in staat om de ene uitzondering te nestelen / try
blok in de andere try
catch
.
Op deze manier kan men kleine blokken code beheren die kunnen werken zonder uw hele mechanisme te verstoren.
try
{
//some code here
try
{
//some thing which throws an exception. For Eg : divide by 0
}
catch (DivideByZeroException dzEx)
{
//handle here only this exception
//throw from here will be passed on to the parent catch block
}
finally
{
//any thing to do after it is done.
}
//resume from here & proceed as normal;
}
catch(Exception e)
{
//handle here
}
Opmerking: vermijd het inslikken van uitzonderingen bij het gooien naar het ouderblok
Best practices
Spiek briefje
DOEN | DO NOT |
---|---|
Controle stroom met controle verklaringen | Regelingsstroom met uitzonderingen |
Houd genegeerde (geabsorbeerde) uitzonderingen bij door te loggen | Negeer uitzondering |
Herhaal de uitzondering met de throw | Re-throw exception - throw new ArgumentNullException() of throw ex |
Gooi vooraf gedefinieerde systeemuitzonderingen | Gooi aangepaste uitzonderingen op dezelfde manier als vooraf gedefinieerde systeemuitzonderingen |
Gebruik aangepaste / vooraf gedefinieerde uitzonderingen als dit cruciaal is voor de toepassingslogica | Gooi aangepaste / vooraf gedefinieerde uitzonderingen om een waarschuwing in flow aan te geven |
Vang uitzonderingen die u wilt verwerken | Vang elke uitzondering |
Beheer bedrijfslogica NIET met uitzonderingen.
Flowregeling mag NIET door uitzonderingen worden gedaan. Gebruik in plaats daarvan voorwaardelijke verklaringen. Als een controle duidelijk kan worden gedaan met de instructie if-else
, gebruik dan geen uitzonderingen omdat dit de leesbaarheid en prestaties vermindert.
Overweeg het volgende fragment van Mr. Bad Practices:
// This is a snippet example for DO NOT
object myObject;
void DoingSomethingWithMyObject()
{
Console.WriteLine(myObject.ToString());
}
Wanneer de uitvoering Console.WriteLine(myObject.ToString());
bereikt Console.WriteLine(myObject.ToString());
applicatie gooit een NullReferenceException. De heer Bad Practices realiseerde zich dat myObject
nul is en bewerkte zijn fragment om NullReferenceException
te vangen en af te handelen:
// This is a snippet example for DO NOT
object myObject;
void DoingSomethingWithMyObject()
{
try
{
Console.WriteLine(myObject.ToString());
}
catch(NullReferenceException ex)
{
// Hmmm, if I create a new instance of object and assign it to myObject:
myObject = new object();
// Nice, now I can continue to work with myObject
DoSomethingElseWithMyObject();
}
}
Aangezien het vorige fragment alleen de uitzonderingslogica bevat, wat moet ik doen als myObject
op dit moment niet nul is? Waar moet ik dit deel van de logica behandelen? Direct na Console.WriteLine(myObject.ToString());
? Hoe zit het na het try...catch
blok try...catch
?
Hoe zit het met Mr. Best Practices? Hoe zou hij hiermee omgaan?
// This is a snippet example for DO
object myObject;
void DoingSomethingWithMyObject()
{
if(myObject == null)
myObject = new object();
// When execution reaches this point, we are sure that myObject is not null
DoSomethingElseWithMyObject();
}
De heer Best Practices bereikte dezelfde logica met minder code en een duidelijke en begrijpelijke logica.
Gooi uitzonderingen NIET opnieuw
Uitgooien van uitzonderingen is duur. Het heeft een negatieve invloed op de prestaties. Voor code die routinematig faalt, kunt u ontwerppatronen gebruiken om prestatieproblemen te minimaliseren. In dit onderwerp worden twee ontwerppatronen beschreven die handig zijn wanneer uitzonderingen de prestaties aanzienlijk kunnen beïnvloeden.
Absorbeer GEEN uitzonderingen zonder logboekregistratie
try
{
//Some code that might throw an exception
}
catch(Exception ex)
{
//empty catch block, bad practice
}
Slik nooit uitzonderingen door. Het negeren van uitzonderingen zal dat moment redden maar zal later een chaos creëren voor onderhoudbaarheid. Wanneer u uitzonderingen vastlegt, moet u altijd de uitzonderingsinstantie registreren, zodat de volledige stacktracering wordt vastgelegd en niet alleen het uitzonderingsbericht.
try
{
//Some code that might throw an exception
}
catch(NullException ex)
{
LogManager.Log(ex.ToString());
}
Vang geen uitzonderingen die u niet aan kunt
Veel bronnen, zoals deze , dringen er sterk op aan om na te denken waarom u een uitzondering maakt op de plaats waar u deze opvangt. Je zou alleen een uitzondering moeten vangen als je het op die locatie aankan. Als je daar iets kunt doen om het probleem te verminderen, zoals een alternatief algoritme proberen, verbinding maken met een back-updatabase, een andere bestandsnaam proberen, 30 seconden wachten en het opnieuw proberen, of een beheerder op de hoogte brengen, kun je de fout opmerken en dat doen. Als er niets is dat u aannemelijk en redelijkerwijs kunt doen, "laat het dan los" en laat de uitzondering op een hoger niveau worden afgehandeld. Als de uitzondering voldoende catastrofaal is en er geen redelijke optie is, behalve dat het hele programma crasht vanwege de ernst van het probleem, laat het dan crashen.
try
{
//Try to save the data to the main database.
}
catch(SqlException ex)
{
//Try to save the data to the alternative database.
}
//If anything other than a SqlException is thrown, there is nothing we can do here. Let the exception bubble up to a level where it can be handled.
Onbehandelde en thread-uitzondering
AppDomain.UnhandledException Deze gebeurtenis geeft een melding van niet-ingevulde uitzonderingen. Hiermee kan de toepassing informatie over de uitzondering registreren voordat de standaardhandler van het systeem de uitzondering aan de gebruiker meldt en de toepassing beëindigt. Als er voldoende informatie beschikbaar is over de status van de toepassing, acties kunnen worden ondernomen - zoals het opslaan van programmagegevens voor later herstel. Voorzichtigheid is geboden, omdat programmagegevens beschadigd kunnen raken wanneer uitzonderingen niet worden verwerkt.
/// <summary>
/// The main entry point for the application.
/// </summary>
[STAThread]
private static void Main(string[] args)
{
AppDomain.CurrentDomain.UnhandledException += new UnhandledExceptionEventHandler(UnhandledException);
}
Application.ThreadException Met deze gebeurtenis kan uw Windows Forms-toepassing anders onverwerkte uitzonderingen verwerken die voorkomen in Windows Forms-threads. Koppel uw gebeurtenishandlers aan de ThreadException-gebeurtenis om met deze uitzonderingen om te gaan, waardoor uw toepassing in een onbekende staat blijft. Waar mogelijk moeten uitzonderingen worden afgehandeld door een gestructureerd uitzonderingsafhandelingsblok.
/// <summary>
/// The main entry point for the application.
/// </summary>
[STAThread]
private static void Main(string[] args)
{
AppDomain.CurrentDomain.UnhandledException += new UnhandledExceptionEventHandler(UnhandledException);
Application.ThreadException += new ThreadExceptionEventHandler(ThreadException);
}
En tot slot de afhandeling van uitzonderingen
static void UnhandledException(object sender, UnhandledExceptionEventArgs e)
{
Exception ex = (Exception)e.ExceptionObject;
// your code
}
static void ThreadException(object sender, ThreadExceptionEventArgs e)
{
Exception ex = e.Exception;
// your code
}
Een uitzondering gooien
Uw code kan en moet vaak een uitzondering genereren wanneer er iets ongewoons is gebeurd.
public void WalkInto(Destination destination)
{
if (destination.Name == "Mordor")
{
throw new InvalidOperationException("One does not simply walk into Mordor.");
}
// ... Implement your normal walking code here.
}