Meilleure pratique pour la gestion des exceptions dans une application Windows Forms?

118

Je suis actuellement en train d'écrire ma première application Windows Forms. J'ai lu quelques livres sur C # maintenant, donc j'ai une assez bonne compréhension des fonctionnalités du langage que C # doit gérer avec les exceptions. Cependant, ils sont tous assez théoriques, donc je n'ai pas encore une idée de la façon de traduire les concepts de base en un bon modèle de gestion des exceptions dans mon application.

Quelqu'un aimerait-il partager des perles de sagesse sur le sujet? Publiez toutes les erreurs courantes que vous avez vues des débutants comme moi faire, et tout conseil général sur la gestion des exceptions d'une manière qui rendra mon application plus stable et plus robuste.

Les principales choses que j'essaye actuellement de travailler sont:

  • Quand dois-je relancer une exception?
  • Dois-je essayer d'avoir un mécanisme central de gestion des erreurs?
  • La gestion des exceptions qui pourraient être levées a-t-elle un impact sur les performances par rapport au test préventif de choses comme l'existence d'un fichier sur le disque?
  • Tout le code exécutable doit-il être inclus dans des blocs try-catch-finally?
  • Y a-t-il des moments où un bloc de capture vide pourrait être acceptable?

Tous les conseils reçus avec gratitude!

Jon Artus
la source

Réponses:

79

Encore quelques bits ...

Vous devez absolument avoir une politique de gestion des exceptions centralisée en place. Cela peut être aussi simple que l'encapsulation Main()dans un try / catch, échouant rapidement avec un message d'erreur gracieux à l'utilisateur. Il s'agit du gestionnaire d'exceptions de «dernier recours».

Les contrôles préventifs sont toujours corrects si possible, mais pas toujours parfaits. Par exemple, entre le code où vous vérifiez l'existence d'un fichier et la ligne suivante où vous l'ouvrez, le fichier peut avoir été supprimé ou un autre problème peut empêcher votre accès. Vous devez encore essayer / attraper / enfin dans ce monde. Utilisez à la fois le contrôle préemptif et try / catch / finally selon le cas.

Ne jamais «avaler» une exception, sauf dans les cas les plus documentés où vous êtes absolument, positivement sûr que l'exception lancée est vivable. Ce ne sera presque jamais le cas. (Et si c'est le cas, assurez-vous de n'avaler que la classe d'exception spécifique - ne jamais avaler System.Exception.)

Lors de la création de bibliothèques (utilisées par votre application), ne pas avaler les exceptions et n'ayez pas peur de laisser les exceptions bouillonner. Ne relancez pas à moins que vous n'ayez quelque chose d'utile à ajouter. Ne faites jamais (en C #) ceci:

throw ex;

Comme vous allez effacer la pile d'appels. Si vous devez relancer (ce qui est parfois nécessaire, par exemple lors de l'utilisation du bloc de gestion des exceptions de la bibliothèque d'entreprise), utilisez ce qui suit:

throw;

À la fin de la journée, la très grande majorité des exceptions levées par une application en cours d'exécution devraient être exposées quelque part. Ils ne doivent pas être exposés aux utilisateurs finaux (car ils contiennent souvent des données propriétaires ou autrement précieuses), mais plutôt généralement enregistrés, les administrateurs étant informés de l'exception. L'utilisateur peut être présenté avec une boîte de dialogue générique, peut-être avec un numéro de référence, pour garder les choses simples.

La gestion des exceptions dans .NET est plus un art qu'une science. Tout le monde aura ses favoris à partager ici. Ce ne sont là que quelques-uns des conseils que j'ai pris en utilisant .NET depuis le premier jour, des techniques qui ont sauvé mon bacon à plus d'une occasion. Votre kilométrage peut varier.

John Rudy
la source
1
Si l'on laisse les exceptions bouillonner, comment l'appelant est-il censé savoir si l'exception indique qu'une opération a échoué mais que le système est fondamentalement en ordre (par exemple, un utilisateur a essayé d'ouvrir un fichier de document corrompu; le fichier ne se charge pas, mais tout autrement devrait être bien), ou si cela indique que le processeur est en feu et qu'il faut se diriger vers les sorties le plus rapidement possible? Quelque chose comme ArgumentException pourrait indiquer l'un ou l'autre, selon les circonstances dans lesquelles il est lancé.
supercat
2
@supercat En écrivant des sous-classes spécifiques de ApplicationExceptionpour les cas d'échec que l'application devrait raisonnablement être en mesure de différencier et de gérer.
Matt Enright
@Matt Enright: Certes, il est possible d'attraper ses propres exceptions, mais je ne suis au courant de rien qui ressemble à distance à une convention selon laquelle les modules qui lancent des exceptions indiquent s'ils indiquent la corruption d'un état extérieur au-delà de ce qu'implique l'échec. Idéalement, une méthode comme SuperDocument.CreateFromFile () réussirait, lèverait une exception CleanFailure ou lèverait une SomethingReallyBadHappenedException. Malheureusement, à moins que l'on n'englobe tout ce qui pourrait lever une exception dans son propre bloc catch, il n'y a aucun moyen de savoir si une InvalidOperationException ...
supercat
@Matt Enright: ... doit être enveloppé dans une CleanFailureException ou une SomethingReallyBadHappenedException. Et tout emballer dans des blocs try-catch individuels irait à l'encontre de l'objectif général d'avoir des exceptions en premier lieu.
supercat du
2
Je pense que c'est une mauvaise conception de la bibliothèque, pour masquer les modes d'échec avec un type d'exception inexact. Ne lancez pas une FileNotFoundException si vous voulez vraiment dire une IOException ou une InvalidDataException, car l'application doit répondre différemment à chaque cas. Des choses comme StackOverflowException ou OutOfMemoryException ne peuvent raisonnablement pas être gérées par une application, alors laissez-les bouillonner, car une application bien comportée a de toute façon le gestionnaire centralisé de «dernier recours» en place.
Matt Enright
63

Il y a un excellent article CodeProject de code ici . Voici quelques faits saillants:

  • Planifiez le pire *
  • Vérifiez tôt
  • Ne faites pas confiance aux données externes
  • Les seuls appareils fiables sont: la vidéo, la souris et le clavier.
  • Les écritures peuvent également échouer
  • Codez en toute sécurité
  • Ne lancez pas de nouvelle exception ()
  • Ne mettez pas d'informations d'exception importantes dans le champ Message
  • Mettre une seule prise (Exception ex) par thread
  • Les exceptions génériques capturées doivent être publiées
  • Log Exception.ToString (); ne jamais se connecter uniquement Exception.Message!
  • N'attrapez pas (Exception) plus d'une fois par thread
  • N'avalez jamais les exceptions
  • Le code de nettoyage doit être placé dans les blocs finally
  • Utilisez "utiliser" partout
  • Ne pas renvoyer de valeurs spéciales en cas d'erreur
  • N'utilisez pas d'exceptions pour indiquer l'absence d'une ressource
  • N'utilisez pas la gestion des exceptions comme moyen de renvoyer des informations à partir d'une méthode
  • Utilisez des exceptions pour les erreurs qui ne doivent pas être ignorées
  • Ne pas effacer la trace de la pile lors de la relance d'une exception
  • Évitez de modifier les exceptions sans ajouter de valeur sémantique
  • Les exceptions doivent être marquées [Serializable]
  • En cas de doute, n'affirmez pas, lancez une exception
  • Chaque classe d'exception doit avoir au moins les trois constructeurs d'origine
  • Soyez prudent lorsque vous utilisez l'événement AppDomain.UnhandledException
  • Ne réinventez pas la roue
  • N'utilisez pas la gestion des erreurs non structurées (VB.Net)
Michée
la source
3
Pourriez-vous m'expliquer un peu plus ce point? "N'utilisez pas d'exceptions pour indiquer l'absence d'une ressource" Je ne suis pas sûr de comprendre la raison derrière cela. Aussi juste une remarque: cette réponse n'explique pas du tout le «pourquoi». Je sais que c'est 5 ans mais ça me dérange encore un peu
Rémi
Le lien vers l'article référencé a expiré. Code Project suggère que l'article a peut-être déménagé ici .
DavidRR
15

Notez que Windows Forms possède son propre mécanisme de gestion des exceptions. Si un bouton du formulaire est cliqué et que son gestionnaire lève une exception qui n'est pas interceptée dans le gestionnaire, Windows Forms affichera sa propre boîte de dialogue d'exception non gérée.

Pour empêcher l'affichage de la boîte de dialogue d'exception non gérée et intercepter ces exceptions pour la journalisation et / ou pour fournir votre propre boîte de dialogue d'erreur, vous pouvez attacher à l'événement Application.ThreadException avant l'appel à Application.Run () dans votre méthode Main ().

utilisateur95680
la source
Merci pour cette suggestion, j'ai appris cela trop tard, je viens de le vérifier dans linqpad, fonctionne comme prévu, le délégué est: void Form1_UIThreadException (expéditeur de l'objet, ThreadExceptionEventArgs t) Une autre bonne source à ce sujet est richnewman.wordpress.com/2007/ 04/08 /… Pour la gestion globale des exceptions non gérées: l'événement AppDomain.UnhandledException concerne les exceptions non gérées levées depuis un thread d'interface utilisateur non principal.
zhaorufei
14

Tous les conseils publiés ici jusqu'à présent sont bons et méritent d'être écoutés.

Une chose sur laquelle je voudrais développer est votre question "La gestion des exceptions qui pourraient être levées a-t-elle un impact sur les performances par rapport au test préventif de choses comme l'existence d'un fichier sur le disque?"

La règle empirique naïve est que «les blocs try / catch sont chers». Ce n'est pas vraiment vrai. Essayer n'est pas cher. C'est la capture, où le système doit créer un objet Exception et le charger avec la trace de pile, c'est cher. Il y a de nombreux cas dans lesquels l'exception est, eh bien, suffisamment exceptionnelle pour qu'il soit parfaitement correct d'encapsuler le code dans un bloc try / catch.

Par exemple, si vous remplissez un dictionnaire, ceci:

try
{
   dict.Add(key, value);
}
catch(KeyException)
{
}

est souvent plus rapide que de faire cela:

if (!dict.ContainsKey(key))
{
   dict.Add(key, value);
}

pour chaque élément que vous ajoutez, car l'exception n'est levée que lorsque vous ajoutez une clé en double. (Les requêtes agrégées LINQ le font.)

Dans l'exemple que vous avez donné, j'utiliserais try / catch presque sans réfléchir. Premièrement, ce n'est pas parce que le fichier existe lorsque vous le vérifiez qu'il existera lorsque vous l'ouvrirez, vous devriez donc vraiment gérer l'exception de toute façon.

Deuxièmement, et je pense que plus important encore, à moins que vous a) votre processus ouvre des milliers de fichiers et b) les chances qu'un fichier qu'il essaie d'ouvrir ne soit pas existant ne sont pas trivialement faibles, la performance de la création de l'exception n'est pas quelque chose que vous '' re va jamais remarquer. De manière générale, lorsque votre programme essaie d'ouvrir un fichier, il n'essaie d'ouvrir qu'un seul fichier. C'est un cas où l'écriture de code plus sûr sera presque certainement meilleure que l'écriture du code le plus rapide possible.

Robert Rossney
la source
3
dans le cas de dict, vous pouvez simplement faire: dict[key] = valuece qui devrait être aussi rapide sinon plus rapide ..
nawfal
9

Voici quelques directives que je suis

  1. Fail-Fast: Il s'agit davantage d'une directive de génération d'exceptions.Pour chaque hypothèse que vous faites et chaque paramètre que vous entrez dans une fonction, effectuez une vérification pour vous assurer que vous commencez avec les bonnes données et que les hypothèses que vous faites sont corrects. Les vérifications typiques incluent, argument non nul, argument dans la plage attendue, etc.

  2. Lors de la relance, conserve la trace de la pile - Cela se traduit simplement par l'utilisation de throw lors de la relance au lieu de lancer une nouvelle Exception (). Sinon, si vous pensez pouvoir ajouter plus d'informations, encapsulez l'exception d'origine en tant qu'exception interne. Mais si vous attrapez une exception uniquement pour la consigner, utilisez définitivement throw;

  3. N'attrapez pas les exceptions que vous ne pouvez pas gérer, alors ne vous inquiétez pas des choses comme OutOfMemoryException, car si elles se produisent, vous ne pourrez pas faire grand-chose de toute façon.

  4. Accrochez les gestionnaires d'exceptions globales et assurez-vous de consigner autant d'informations que possible. Pour winforms, accrochez à la fois les événements d'exception non gérés de domaine d'application et de thread.

  5. Les performances ne doivent être prises en considération que lorsque vous avez analysé le code et constaté qu'il provoque un goulot d'étranglement des performances, par défaut, optimisez la lisibilité et la conception. Donc, à propos de votre question initiale sur la vérification de l'existence du fichier, je dirais que cela dépend.Si vous pouvez faire quelque chose pour que le fichier ne soit pas là, alors oui, faites cette vérification sinon si tout ce que vous allez faire est de lever une exception si le fichier est pas là alors je ne vois pas le point.

  6. Il y a certainement des moments où des blocs catch vides sont nécessaires, je pense que les gens qui disent le contraire n'ont pas travaillé sur des bases de code qui ont évolué au cours de plusieurs versions. Mais ils devraient être commentés et examinés pour s'assurer qu'ils sont vraiment nécessaires. L'exemple le plus typique est que les développeurs utilisent try / catch pour convertir une chaîne en entier au lieu d'utiliser ParseInt ().

  7. Si vous vous attendez à ce que l'appelant de votre code puisse gérer les conditions d'erreur, créez des exceptions personnalisées qui détaillent la situation inattendue et fournissent des informations pertinentes. Sinon, respectez le plus possible les types d'exceptions intégrés.

Sijin
la source
À quoi sert le raccordement des gestionnaires d'exceptions non gérées de domaine d'application et de thread? Si vous utilisez simplement Appdomain.UnhandledException, n'est-ce pas le plus générique qui va tout attraper?
Quagmire
Vouliez-vous dire gérer l' Application.ThreadExceptionévénement lorsque vous avez fait référence à l'événement "exception de thread non gérée"?
Jeff B du
4

J'aime la philosophie de ne rien attraper que je n'ai pas l'intention de manipuler, quel que soit le sens de manipulation dans mon contexte particulier.

Je déteste quand je vois du code tel que:

try
{
   // some stuff is done here
}
catch
{
}

J'ai vu cela de temps en temps et il est assez difficile de trouver des problèmes quand quelqu'un «mange» les exceptions. Un collègue que j'ai eu fait cela et cela a tendance à contribuer à un flux constant de problèmes.

Je relance s'il y a quelque chose que ma classe particulière doit faire en réponse à une exception mais que le problème doit être évacué, quelle que soit la méthode où cela s'est produit.

Je pense que le code devrait être rédigé de manière proactive et que les exceptions devraient concerner des situations exceptionnelles, et non éviter de tester les conditions.

itsmatt
la source
@Kiquenet Désolé, je n'étais pas très clair. Ce que je voulais dire: ne faites pas de telles captures vides, ajoutez plutôt un gestionnaire à Dispatcher.UnhandledException , et ajoutez au moins un journal pour qu'il ne soit pas mangé sans fil d'Ariane :) Mais à moins que vous n'ayez l'exigence d'un composant silencieux, vous devez toujours inclure des exceptions dans votre conception. Lancez-les quand ils doivent être lancés, faites des contrats clairs pour vos interfaces / API / toute classe.
LuckyLikey
4

Je suis juste sur le point de sortir, mais je vais vous expliquer brièvement où utiliser la gestion des exceptions. J'essaierai d'aborder vos autres points à mon retour :)

  1. Vérifiez explicitement toutes les conditions d'erreur connues *
  2. Ajoutez un try / catch autour du code si vous n'êtes pas sûr de pouvoir gérer tous les cas
  3. Ajoutez un try / catch autour du code si l'interface .NET que vous appelez lève une exception
  4. Ajoutez un essai / capture autour du code s'il franchit un seuil de complexité pour vous
  5. Ajoutez un try / catch autour du code si pour une vérification de cohérence: vous affirmez que CELA NE DEVRAIT JAMAIS SE PRODUIRE
  6. En règle générale, je n'utilise pas d'exceptions en remplacement des codes de retour. C'est bien pour .NET, mais pas pour moi. J'ai cependant des exceptions (hehe) à cette règle, cela dépend également de l'architecture de l'application sur laquelle vous travaillez.

*Raisonnable. Il n'est pas nécessaire de vérifier si, par exemple, un rayon cosmique a frappé vos données, provoquant le retournement de quelques bits. Comprendre ce qui est «raisonnable» est une compétence acquise pour un ingénieur. C'est difficile à quantifier, mais facile à comprendre. Autrement dit, je peux facilement expliquer pourquoi j'utilise un try / catch dans un cas particulier, mais j'ai du mal à en imprégner un autre avec cette même connaissance.

Pour ma part, j'ai tendance à m'éloigner des architectures fortement basées sur les exceptions. try / catch n'a pas de hit de performance en tant que tel, le hit arrive lorsque l'exception est levée et le code devra peut-être remonter plusieurs niveaux de la pile d'appels avant que quelque chose ne le gère.

pezi_pink_squirrel
la source
4

La règle d'or à laquelle on a essayé de s'en tenir est de gérer l'exception aussi près que possible de la source.

Si vous devez relancer une exception, essayez d'y ajouter, relancer une FileNotFoundException n'aide pas beaucoup, mais lancer une ConfigurationFileNotFoundException lui permettra d'être capturée et d'agir quelque part dans la chaîne.

Une autre règle que j'essaie de suivre est de ne pas utiliser try / catch comme une forme de flux de programme, donc je vérifie les fichiers / connexions, je m'assure que les objets ont été lancés, etc. avant de les utiliser. Try / catch devrait être pour les exceptions, des choses que vous ne pouvez pas contrôler.

Comme pour un bloc catch vide, si vous faites quelque chose d'important dans le code qui a généré l'exception, vous devez relancer l'exception au minimum. S'il n'y a aucune conséquence du code qui a jeté l'exception ne s'exécutant pas, pourquoi l'avez-vous écrit en premier lieu.


la source
Cette "règle d'or" est au mieux arbitraire.
Evan Harper
3

vous pouvez intercepter l'événement ThreadException.

  1. Sélectionnez un projet d'application Windows dans l'Explorateur de solutions.

  2. Ouvrez le fichier Program.cs généré en double-cliquant dessus.

  3. Ajoutez la ligne de code suivante en haut du fichier de code:

    using System.Threading;
  4. Dans la méthode Main (), ajoutez ce qui suit comme première ligne de la méthode:

    Application.ThreadException += new ThreadExceptionEventHandler(Application_ThreadException);
  5. Ajoutez ce qui suit sous la méthode Main ():

    static void Application_ThreadException(object sender, ThreadExceptionEventArgs e)
    {
        // Do logging or whatever here
        Application.Exit();
    }
  6. Ajoutez du code pour gérer l'exception non gérée dans le gestionnaire d'événements. Toute exception qui n'est gérée nulle part ailleurs dans l'application est gérée par le code ci-dessus. Le plus souvent, ce code doit consigner l'erreur et afficher un message à l'utilisateur.

référence: https://blogs.msmvps.com/deborahk/global-exception-handler-winforms/

Omid-RH
la source
@Kiquenet désolé, je ne sais pas pour VB
Omid-RH
2

Les exceptions sont coûteuses mais nécessaires. Vous n'avez pas besoin de tout emballer dans une tentative de capture, mais vous devez vous assurer que les exceptions sont toujours interceptées éventuellement. Cela dépendra en grande partie de votre conception.

Ne relancez pas si laisser l'exception augmenter fera tout aussi bien. Ne laissez jamais les erreurs passer inaperçues.

exemple:

void Main()
{
  try {
    DoStuff();
  }
  catch(Exception ex) {
    LogStuff(ex.ToString());
  }

void DoStuff() {
... Stuff ...
}

Si DoStuff tourne mal, vous voudrez quand même qu'il soit libéré sous caution. L'exception sera lancée à main et vous verrez le train d'événements dans la trace de pile de ex.

Echostorm
la source
1

Quand dois-je relancer une exception?

Partout, mais les méthodes de l'utilisateur final ... comme les gestionnaires de clic de bouton

Dois-je essayer d'avoir un mécanisme central de gestion des erreurs?

J'écris un fichier journal ... assez facile pour une application WinForm

La gestion des exceptions qui pourraient être levées a-t-elle un impact sur les performances par rapport au test préventif de choses comme l'existence d'un fichier sur le disque?

Je ne suis pas sûr de cela, mais je pense que c'est une bonne pratique de faire des exceptions ... Je veux dire que vous pouvez demander si un fichier existe et s'il ne lance pas une FileNotFoundException

Tout le code exécutable doit-il être inclus dans des blocs try-catch-finally?

ouais

Y a-t-il des moments où un bloc de capture vide pourrait être acceptable?

Oui, disons que vous voulez afficher une date, mais vous n'avez aucune idée de la façon dont cette date a été stockée (jj / mm / aaaa, mm / jj / aaaa, etc.), vous essayez de l'analyser, mais si elle échoue, continuez. Si cela ne vous concerne pas ... je dirais que oui, il y a

Sebagomez
la source
1

La seule chose que j'ai apprise très rapidement a été de renfermer absolument chaque morceau de code qui interagit avec tout ce qui se trouve en dehors du flux de mon programme (c'est-à-dire le système de fichiers, les appels de base de données, l'entrée utilisateur) avec des blocs try-catch. Try-catch peut entraîner un impact négatif sur les performances, mais généralement à ces endroits de votre code, cela ne sera pas perceptible et il se rentabilisera en toute sécurité. vraiment besoin de poster un message, mais si vous ne l'attrapez pas, il lancera une erreur d'exception non gérée à l'utilisateur.

J'ai utilisé des blocs de capture vides dans des endroits où l'utilisateur peut faire quelque chose qui n'est pas vraiment "incorrect", mais cela peut lever une exception ... un exemple qui me vient à l'esprit est dans un GridView si l'utilisateur DoubleClique sur l'espace réservé gris cellule en haut à gauche, il déclenchera l'événement CellDoubleClick, mais la cellule n'appartient pas à une ligne. Dans ce cas, vous ne

BKimmel
la source
1

Lors de la relance d'une exception, le mot clé jeté par lui-même. Cela lèvera l'exception interceptée et pourra toujours utiliser la trace de pile pour voir d'où elle vient.

Try
{
int a = 10 / 0;
}
catch(exception e){
//error logging
throw;
}

cela entraînera la fin de la trace de pile dans l'instruction catch. (éviter ça)

catch(Exception e)
// logging
throw e;
}
Brad8118
la source
cela s'applique-t-il toujours aux versions les plus récentes de .NET Framework et .NET Core?
LuckyLikey
1

Dans mon expérience, j'ai jugé bon d'attraper des exceptions quand je sais que je vais les créer. Pour les cas où je suis dans une application Web et que je fais une Response.Redirect, je sais que je vais recevoir une exception System.ThreadAbortException. Comme c'est intentionnel, j'ai juste une prise pour le type spécifique et je l'avale.

try
{
/*Doing stuff that may cause an exception*/
Response.Redirect("http:\\www.somewhereelse.com");
}
catch (ThreadAbortException tex){/*Ignore*/}
catch (Exception ex){/*HandleException*/}
Jeff Keslinke
la source
1

Je suis profondément d'accord avec la règle de:

  • Ne laissez jamais les erreurs passer inaperçues.

La raison en est que:

  • Lorsque vous écrivez le code pour la première fois, vous n'aurez probablement pas la connaissance complète du code tiers, du fichier .NET FCL ou des dernières contributions de vos collègues. En réalité, vous ne pouvez pas refuser d'écrire du code tant que vous ne connaissez pas bien toutes les possibilités d'exception. Alors
  • Je trouve constamment que j'utilise try / catch (Exception ex) simplement parce que je veux me protéger des choses inconnues, et, comme vous l'avez remarqué, j'attrape Exception, pas la plus spécifique comme OutOfMemoryException etc. Et, je fais toujours l'exception être poppé vers moi (ou le QA) par ForceAssert.AlwaysAssert (false, ex.ToString ());

ForceAssert.AlwaysAssert est ma manière personnelle de Trace.Assert, que la macro DEBUG / TRACE soit définie ou non.

Le cycle de développement peut-être: j'ai remarqué le vilain dialogue Assert ou quelqu'un d'autre m'en a parlé, puis je reviens au code et trouve la raison de lever l'exception et décide comment la traiter.

De cette façon, je peux écrire MON code en peu de temps et me protéger du domaine inconnu, mais étant toujours remarqué si des choses anormales se sont produites, de cette façon, le système est devenu sûr et plus sûr.

Je sais que beaucoup d'entre vous ne seront pas d'accord avec moi car un développeur devrait connaître chaque détail de son code, franchement, je suis aussi un puriste dans l'ancien temps. Mais aujourd'hui, j'ai appris que la politique ci-dessus est plus pragmatique.

Pour le code WinForms, une règle d'or à laquelle j'obéis toujours est:

  • Toujours essayer / attraper (exception) le code de votre gestionnaire d'événements

cela protégera votre interface utilisateur en étant toujours utilisable.

Pour l'atteinte des performances, la pénalité de performances se produit uniquement lorsque le code atteint catch, l'exécution du code try sans l'exception réelle déclenchée n'a pas d'effet significatif.

L'exception devrait se produire avec peu de chance, sinon ce ne sont pas des exceptions.

zhaorufei
la source
-1

Vous devez penser à l'utilisateur. Le crash de l'application est le dernierchose que l'utilisateur veut. Par conséquent, toute opération qui peut échouer doit avoir un bloc try catch au niveau de l'interface utilisateur. Il n'est pas nécessaire d'utiliser try catch dans chaque méthode, mais chaque fois que l'utilisateur fait quelque chose, il doit être capable de gérer des exceptions génériques. Cela ne vous libère en aucun cas de tout vérifier pour éviter les exceptions dans le premier cas, mais il n'y a pas d'application complexe sans bogues et le système d'exploitation peut facilement ajouter des problèmes inattendus, vous devez donc anticiper l'inattendu et vous assurer si un utilisateur souhaite en utiliser un opération, il n'y aura pas de perte de données car l'application se bloque. Il n'est pas nécessaire de laisser votre application planter, si vous rencontrez des exceptions, elle ne sera jamais dans un état indéterminé et l'utilisateur est TOUJOURS gêné par un crash. Même si l'exception est au plus haut niveau, ne pas planter signifie que l'utilisateur peut rapidement reproduire l'exception ou au moins enregistrer le message d'erreur et donc grandement vous aider à résoudre le problème. Certainement beaucoup plus que d'obtenir un simple message d'erreur et de ne voir que la boîte de dialogue d'erreur Windows ou quelque chose du genre.

C'est pourquoi vous ne devez JAMAIS être vaniteux et penser que votre application ne présente aucun bogue, ce n'est pas garanti. Et c'est un très petit effort pour envelopper quelques blocs try catch sur le code approprié et afficher un message d'erreur / enregistrer l'erreur.

En tant qu'utilisateur, je suis vraiment énervé chaque fois qu'un navigateur ou une application de bureau ou quoi que ce soit se bloque. Si l'exception est si élevée que l'application ne peut pas continuer, il est préférable d'afficher ce message et de dire à l'utilisateur quoi faire (redémarrer, corriger certains paramètres du système d'exploitation, signaler le bogue, etc.) que de simplement planter et c'est tout.

Terry Bogard
la source
Pouvez-vous essayer d'écrire des réponses moins comme une diatribe et plutôt essayer d'être plus précis et essayer de prouver votre point? Jetez également un œil à Comment répondre .
LuckyLikey