C# Language
Gestion des exceptions
Recherche…
Gestion des exceptions de base
try
{
/* code that could throw an exception */
}
catch (Exception ex)
{
/* handle the exception */
}
Notez que la gestion de toutes les exceptions avec le même code n'est souvent pas la meilleure approche.
Ceci est couramment utilisé lorsque toutes les routines de gestion des exceptions internes échouent, en dernier recours.
Gestion de types d'exceptions spécifiques
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 */
}
Veillez à ce que les exceptions soient évaluées dans l'ordre et l'héritage est appliqué. Vous devez donc commencer par les plus spécifiques et terminer par leur ancêtre. A tout moment, un seul bloc catch sera exécuté.
Utiliser l'objet exception
Vous êtes autorisé à créer et à lancer des exceptions dans votre propre code. L'instanciation d'une exception se fait de la même manière que tout autre objet C #.
Exception ex = new Exception();
// constructor with an overload that takes a message string
Exception ex = new Exception("Error message");
Vous pouvez ensuite utiliser le mot-clé throw
pour déclencher l'exception:
try
{
throw new Exception("Error");
}
catch (Exception ex)
{
Console.Write(ex.Message); // Logs 'Error' to the output window
}
Remarque: Si vous lancez une nouvelle exception dans un bloc catch, vérifiez que l'exception d'origine est transmise en tant qu '"exception interne", par exemple
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());
}
}
Dans ce cas, il est supposé que l'exception ne peut pas être gérée mais certaines informations utiles sont ajoutées au message (et l'exception d'origine peut toujours être accédée via ex.InnerException
par un bloc d'exception externe).
Il montrera quelque chose comme:
System.DivideByZeroException: impossible de diviser par b car il est zéro ---> System.DivideByZeroException: tentative de division par zéro.
à UserQuery.g__DoSomething0_0 () dans C: [...] \ LINQPadQuery.cs: ligne 36
--- Fin de trace de pile d'exception interne ---
à UserQuery.g__DoSomething0_0 () dans C: [...] \ LINQPadQuery.cs: ligne 42
à UserQuery.Main () dans C: [...] \ LINQPadQuery.cs: ligne 55
Si vous essayez cet exemple dans LinqPad, vous remarquerez que les numéros de ligne ne sont pas très significatifs (ils ne vous aident pas toujours). Cependant, le fait de transmettre un texte d'erreur utile, comme suggéré ci-dessus, réduit considérablement le temps nécessaire pour localiser l'erreur, ce qui est clairement dans cet exemple la ligne
c = a / b;
dans la fonction DoSomething()
.
Bloquer enfin
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 */
}
Le bloc try / catch / finally
peut être très utile lors de la lecture de fichiers.
Par exemple:
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.
}
Un bloc try doit être suivi soit d'un bloc catch
soit d'un bloc finally
. Cependant, comme il n'y a pas de bloc catch, l'exécution provoquera une terminaison. Avant la fin, les instructions contenues dans le bloc finally seront exécutées.
Dans la lecture de fichiers, nous aurions pu utiliser un bloc using
FileStream
(ce OpenRead
renvoie OpenRead
) implémente IDisposable
.
Même s'il existe une instruction de return
dans le bloc try
, le bloc finally
sera généralement exécuté; il y a quelques cas où cela ne va pas:
- Lorsqu'un StackOverflow se produit .
-
Environment.FailFast
- Le processus d'application est interrompu, généralement par une source externe.
Implémentation d'IErrorHandler pour les services WCF
L'implémentation d'IErrorHandler pour les services WCF est un excellent moyen de centraliser la gestion des erreurs et la journalisation. L'implémentation présentée ici doit intercepter toute exception non gérée à la suite d'un appel à l'un de vos services WCF. Cet exemple montre également comment renvoyer un objet personnalisé et comment renvoyer JSON plutôt que le code XML par défaut.
Implémenter 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
Dans cet exemple, nous attachons le gestionnaire au comportement du service. Vous pouvez également associer ceci à IEndpointBehavior, IContractBehavior ou IOperationBehavior de la même manière.
Attacher aux comportements de service:
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 dans 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>
...
Voici quelques liens utiles sur ce sujet:
https://msdn.microsoft.com/en-us/library/system.servicemodel.dispatcher.ierrorhandler(v=vs.100).aspx
Autres exemples:
IErrorHandler renvoie un corps de message incorrect lorsque le code d'état HTTP est 401 Non autorisé
IErrorHandler ne semble pas gérer mes erreurs dans WCF .. des idées?
Comment définissez-vous l'en-tête Content-Type pour une requête HttpClient?
Création d'exceptions personnalisées
Vous êtes autorisé à implémenter des exceptions personnalisées pouvant être lancées comme toute autre exception. Cela a du sens lorsque vous voulez distinguer vos exceptions des autres erreurs lors de l'exécution.
Dans cet exemple, nous allons créer une exception personnalisée pour gérer clairement les problèmes éventuels de l'application tout en analysant une entrée complexe.
Création d'une classe d'exception personnalisée
Pour créer une exception personnalisée, créez une sous-classe d' Exception
:
public class ParserException : Exception
{
public ParserException() :
base("The parsing went wrong and we have no additional information.") { }
}
Les exceptions personnalisées deviennent très utiles lorsque vous souhaitez fournir des informations supplémentaires au receveur:
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;}
}
Maintenant, quand vous catch(ParserException x)
vous aurez une sémantique supplémentaire pour affiner la gestion des exceptions.
Les classes personnalisées peuvent implémenter les fonctionnalités suivantes pour prendre en charge des scénarios supplémentaires.
lancer à nouveau
Pendant le processus d'analyse, l'exception d'origine est toujours intéressante. Dans cet exemple, il s'agit d'une FormatException
car le code tente d'analyser un morceau de chaîne, qui devrait être un nombre. Dans ce cas, l'exception personnalisée devrait prendre en charge l'inclusion de « InnerException »:
//new constructor:
ParserException(string msg, Exception inner) : base(msg, inner) {
}
sérialisation
Dans certains cas, vos exceptions peuvent avoir à franchir les limites de AppDomain. C'est le cas si votre analyseur s'exécute dans son propre AppDomain pour prendre en charge le rechargement à chaud de nouvelles configurations d'analyseur. Dans Visual Studio, vous pouvez utiliser le modèle Exception
pour générer du code comme celui-ci.
[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)
{}
}
Utiliser l'Exception Parser
try
{
Process.StartRun(fileName)
}
catch (ParserException ex)
{
Console.WriteLine($"{ex.Message} in ${ex.FileName}:${ex.LineNumber}");
}
catch (PostProcessException x)
{
...
}
Vous pouvez également utiliser des exceptions personnalisées pour intercepter et encapsuler des exceptions. De cette façon, de nombreuses erreurs différentes peuvent être converties en un seul type d'erreur plus utile pour l'application:
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);
}
Lorsque vous gérez des exceptions en levant vos propres exceptions personnalisées, vous devez généralement inclure une référence à l'exception d'origine dans la InnerException
, comme indiqué ci-dessus.
Problèmes de sécurité
Si exposer la raison de l'exception peut compromettre la sécurité en permettant aux utilisateurs de voir le fonctionnement interne de votre application, il peut être une mauvaise idée d'envelopper l'exception interne. Cela peut s'appliquer si vous créez une bibliothèque de classes qui sera utilisée par d'autres.
Voici comment vous pouvez générer une exception personnalisée sans encapsuler l'exception interne:
try
{
// ...
}
catch (SomeStandardException ex)
{
// ...
throw new MyCustomException(someMessage);
}
Conclusion
Lorsque vous déclenchez une exception personnalisée (avec une nouvelle enveloppe ou une nouvelle exception non emballée), vous devez générer une exception significative pour l'appelant. Par exemple, un utilisateur d'une bibliothèque de classes peut ne pas savoir comment cette bibliothèque exécute son travail interne. Les exceptions levées par les dépendances de la bibliothèque de classes ne sont pas significatives. Au contraire, l'utilisateur souhaite une exception qui concerne la manière dont la bibliothèque de classes utilise ces dépendances de manière erronée.
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);
}
Exception Anti-patrons
Exceptions à la déglutition
Il faut toujours relancer l’exception de la manière suivante:
try
{
...
}
catch (Exception ex)
{
...
throw;
}
Relancer une exception comme ci-dessous masquera l'exception d'origine et perdra la trace de la pile d'origine. On ne devrait jamais faire ça! La trace de la pile avant la capture et la relance sera perdue.
try
{
...
}
catch (Exception ex)
{
...
throw ex;
}
Gestion des exceptions de baseball
Il ne faut pas utiliser les exceptions comme substitut aux constructions de contrôle de flux normales comme les instructions if-then et les boucles while. Cet anti-pattern est parfois appelé gestion des exceptions de baseball .
Voici un exemple d'anti-pattern:
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());
}
Voici une meilleure façon de le faire:
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());
attraper (Exception)
Il n'y a presque pas (certaines ne disent rien!) De raisons pour intercepter le type d'exception générique dans votre code. Vous ne devriez intercepter que les types d'exception que vous prévoyez, car vous masquez autrement les bogues dans votre code.
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?
}
Mieux vaut faire:
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");
}
Si une autre exception se produit, nous autorisons délibérément l'application à tomber en panne, elle intervient donc directement dans le débogueur et nous pouvons résoudre le problème. Nous ne devons pas expédier un programme où toute autre exception que celle-ci se produit de toute façon, donc ce n'est pas un problème d'avoir un crash.
Ce qui suit est un mauvais exemple, car il utilise des exceptions pour contourner une erreur de programmation. Ce n'est pas pour ça qu'ils sont conçus.
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.
}
Exceptions globales / exceptions multiples d'une méthode
Qui dit que vous ne pouvez pas lancer plusieurs exceptions dans une méthode. Si vous n'avez pas l'habitude de jouer avec AggregateExceptions, vous pouvez être tenté de créer votre propre structure de données pour représenter de nombreuses erreurs. Il y a bien sûr une autre structure de données qui n'est pas une exception serait plus idéale comme les résultats d'une validation. Même si vous jouez avec AggregateExceptions, vous êtes peut-être du côté de la réception et vous les manipulez toujours sans vous rendre compte qu'elles peuvent vous être utiles.
Il est tout à fait plausible de faire exécuter une méthode et même si cela sera un échec dans son ensemble, vous voudrez mettre en évidence plusieurs choses qui ont mal tourné dans les exceptions lancées. A titre d'exemple, ce comportement peut être vu avec le fonctionnement des méthodes Parallel, une tâche divisée en plusieurs threads et un nombre quelconque d'entre elles pouvant générer des exceptions et cela doit être signalé. Voici un exemple stupide de la façon dont vous pourriez en bénéficier:
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);
}
}
Nidification des exceptions et essayez les blocs de capture.
On peut imbriquer une exception / try
bloc catch
dans l'autre.
De cette façon, vous pouvez gérer de petits blocs de code capables de fonctionner sans perturber l’ensemble de votre mécanisme.
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
}
Remarque: évitez les exceptions de déglutition lors du lancement sur le bloc catch parent
Les meilleures pratiques
Cheatsheet
FAIRE | Ne pas |
---|---|
Contrôle du flux avec des instructions de contrôle | Contrôle des flux avec des exceptions |
Suivre les exceptions ignorées (absorbées) en se connectant | Ignorer l'exception |
Répétez l'exception en utilisant throw | Re-jeter une exception - throw new ArgumentNullException() ou throw ex |
Lancer des exceptions système prédéfinies | Jeter des exceptions personnalisées similaires aux exceptions système prédéfinies |
Jeter une exception personnalisée / prédéfinie si elle est cruciale pour la logique de l'application | Lancer des exceptions personnalisées / prédéfinies pour indiquer un avertissement dans le flux |
Catch exceptions que vous souhaitez gérer | Attraper toutes les exceptions |
NE PAS gérer la logique métier avec des exceptions.
Le contrôle de flux ne doit PAS être effectué par des exceptions. Utilisez plutôt des instructions conditionnelles. Si un contrôle peut être effectué avec l'instruction if-else
clairement, n'utilisez pas les exceptions car cela réduit la lisibilité et les performances.
Considérez l'extrait suivant de Mr. Bad Practices:
// This is a snippet example for DO NOT
object myObject;
void DoingSomethingWithMyObject()
{
Console.WriteLine(myObject.ToString());
}
Lorsque l'exécution atteint Console.WriteLine(myObject.ToString());
l'application lancera une exception NullReferenceException. M. Bad Practices s'est rendu compte que myObject
était nul et a modifié son extrait pour intercepter et gérer NullReferenceException
:
// 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();
}
}
Comme l'extrait de myObject
précédent ne couvre que la logique d'exception, que dois-je faire si myObject
n'est pas nul à ce stade? Où devrais-je couvrir cette partie de la logique? Juste après Console.WriteLine(myObject.ToString());
? Qu'en est-il après le try...catch
block?
Qu'en est-il de Mr. Best Practices? Comment va-t-il gérer ça?
// 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();
}
M. Best Practices a atteint la même logique avec moins de code et une logique claire et compréhensible.
NE PAS rejeter les exceptions
Relancer les exceptions est coûteux. Cela a un impact négatif sur les performances. Pour le code qui échoue régulièrement, vous pouvez utiliser des modèles de conception pour minimiser les problèmes de performances. Cette rubrique décrit deux modèles de conception utiles lorsque des exceptions peuvent avoir un impact significatif sur les performances.
NE PAS absorber les exceptions sans enregistrement
try
{
//Some code that might throw an exception
}
catch(Exception ex)
{
//empty catch block, bad practice
}
Ne jamais avaler les exceptions. Ignorer les exceptions sauvera ce moment mais créera un chaos pour la maintenabilité plus tard. Lors de la journalisation des exceptions, vous devez toujours consigner l'instance d'exception afin que la trace complète de la pile soit consignée et non uniquement le message d'exception.
try
{
//Some code that might throw an exception
}
catch(NullException ex)
{
LogManager.Log(ex.ToString());
}
Ne pas intercepter les exceptions que vous ne pouvez pas gérer
De nombreuses ressources, telles que celle-ci , vous invitent fortement à réfléchir aux raisons pour lesquelles vous attrapez une exception à l'endroit où vous la capturez. Vous ne devriez attraper une exception que si vous pouvez la gérer à cet endroit. Si vous pouvez faire quelque chose pour atténuer le problème, par exemple essayer un autre algorithme, vous connecter à une base de données de sauvegarde, essayer un autre nom de fichier, attendre 30 secondes et réessayer ou avertir un administrateur, vous pouvez détecter l'erreur. S'il n'y a rien que vous puissiez faire de manière plausible et raisonnable, il suffit de "laisser aller" et de laisser l'exception être traitée à un niveau supérieur. Si l'exception est suffisamment catastrophique et qu'il n'y a pas d'autre option raisonnable que le blocage complet du programme en raison de la gravité du problème, laissez-le tomber en panne.
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.
Exception non gérée et thread
AppDomain.UnhandledException Cet événement fournit une notification des exceptions non interceptées. Il permet à l'application de consigner des informations sur l'exception avant que le gestionnaire par défaut du système ne signale l'exception à l'utilisateur et qu'il mette fin à l'application. des actions peuvent être entreprises - telles que la sauvegarde des données du programme pour une récupération ultérieure. Une mise en garde est recommandée, car les données du programme peuvent être corrompues lorsque des exceptions ne sont pas gérées.
/// <summary>
/// The main entry point for the application.
/// </summary>
[STAThread]
private static void Main(string[] args)
{
AppDomain.CurrentDomain.UnhandledException += new UnhandledExceptionEventHandler(UnhandledException);
}
Application.ThreadException Cet événement permet à votre application Windows Forms de gérer les exceptions non gérées qui se produisent dans les threads Windows Forms. Attachez vos gestionnaires d'événements à l'événement ThreadException pour gérer ces exceptions, ce qui laissera votre application dans un état inconnu. Dans la mesure du possible, les exceptions doivent être gérées par un bloc de gestion des exceptions structuré.
/// <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);
}
Et enfin la gestion des exceptions
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
}
Lancer une exception
Votre code peut, et devrait souvent, lancer une exception lorsque quelque chose d'inhabituel s'est produit.
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.
}