J'ai lu les conseils sur cette question sur la manière de traiter une exception aussi près que possible de son origine.
Mon dilemme sur la meilleure pratique est de savoir si l'on doit utiliser un try / catch / enfin pour retourner une énumération (ou un int qui représente une valeur, 0 pour l'erreur, 1 pour ok, 2 pour l'avertissement, etc., selon le cas) afin que une réponse est toujours en ordre, ou faut-il laisser passer l'exception pour que la partie appelante s'en occupe?
D'après ce que je peux comprendre, cela pourrait être différent selon le cas, donc le conseil d'origine semble étrange.
Par exemple, sur un service Web, vous voudrez toujours retourner un état bien sûr, donc toute exception doit être traitée sur place, mais disons à l'intérieur d'une fonction qui publie / obtient des données via http, vous voudriez que le exception (par exemple dans le cas de 404) pour simplement passer à celui qui l'a tiré. Si vous ne le faites pas, vous devrez créer un moyen d'informer la partie appelante de la qualité du résultat (erreur: 404), ainsi que du résultat lui-même.
Bien qu'il soit possible d'essayer d'attraper l'exception 404 à l'intérieur de la fonction d'assistance qui obtient / publie les données, devriez-vous? Est-ce seulement moi qui utilise un petit entier pour désigner les états dans le programme (et les documenter de manière appropriée bien sûr), puis utiliser ces informations à des fins de validation de bon sens (tout va bien / gestion des erreurs) à l'extérieur?
Mise à jour: je m'attendais à une exception fatale / non fatale pour la classification principale, mais je ne voulais pas l'inclure afin de ne pas nuire aux réponses. Permettez-moi de clarifier la question: gérer les exceptions levées, et non lever des exceptions. L'effet souhaité: détectez une erreur et essayez de la récupérer. Si la récupération n'est pas possible, fournissez les commentaires les plus significatifs.
Encore une fois, avec l'exemple http get / post, la question est, devez-vous fournir un nouvel objet qui décrit ce qui est arrivé à l'appelant d'origine? Si cet assistant était dans une bibliothèque que vous utilisez, vous attendriez-vous à ce qu'il vous fournisse un code d'état pour l'opération, ou l'inclueriez-vous dans un bloc try-catch? Si vous le concevez , fourniriez-vous un code d'état ou lèveriez-vous une exception et laisser le niveau supérieur le traduire en code / message d'état à la place?
Synopsis: Comment choisissez-vous si un morceau de code au lieu de produire une exception, retourne un code d'état avec les résultats qu'il peut produire?
la source
Réponses:
Des exceptions doivent être utilisées pour des conditions exceptionnelles. Lancer une exception revient à dire: "Je ne peux pas gérer cette condition ici; quelqu'un plus haut dans la pile des appels peut-il attraper cela pour moi et le gérer?"
Renvoyer une valeur peut être préférable, s'il est clair que l'appelant prendra cette valeur et fera quelque chose de significatif avec elle. Cela est particulièrement vrai si le lancement d'une exception a des implications en termes de performances, c'est-à-dire qu'elle peut se produire dans une boucle étroite. Lancer une exception prend beaucoup plus de temps que de renvoyer une valeur (d'au moins deux ordres de grandeur).
Les exceptions ne doivent jamais être utilisées pour implémenter la logique du programme. En d'autres termes, ne lancez pas d'exception pour faire quelque chose; lever une exception pour déclarer que cela ne pouvait pas être fait.
la source
Un bon conseil que j'ai lu une fois était de lever des exceptions lorsque vous ne pouvez pas progresser compte tenu de l'état des données que vous traitez, mais si vous avez une méthode qui peut lever une exception, fournissez également si possible une méthode pour affirmer si les données sont réellement valide avant l'appel de la méthode.
Par exemple, System.IO.File.OpenRead () lèvera une FileNotFoundException si le fichier fourni n'existe pas, mais il fournit également une méthode .Exists () qui renvoie une valeur booléenne indiquant si le fichier est présent que vous devez appeler avant appeler OpenRead () pour éviter toute exception inattendue.
Pour répondre à la partie "quand dois-je traiter une exception" de la question, je dirais où vous pouvez réellement faire quelque chose. Si votre méthode ne peut pas traiter une exception levée par une méthode qu'elle appelle, ne l'attrapez pas. Laissez-le monter plus haut dans la chaîne d'appel vers quelque chose qui puisse y faire face. Dans certains cas, il peut simplement s'agir d'un enregistreur écoutant Application.UnhandledException.
la source
C'est une conception terrible. Ne «masquez» pas une exception en traduisant en un code numérique. Laissez-le comme une exception appropriée et sans ambiguïté.
C'est à cela que servent les exceptions.
Ce n'est pas du tout une vérité universelle . C'est une bonne idée parfois. D'autres fois, ce n'est pas aussi utile.
la source
if
instructions (parfois) lourdes au lieu d'une gestion des exceptions (parfois) plus simple. La réponse ("Comment choisir ...") est simple. Non . Je pense que cela ajoute à la conversation. Vous êtes cependant libre d'ignorer cette réponse.Je suis d'accord avec S.Lott . Attraper l'exception aussi près que possible de la source peut être une bonne ou une mauvaise idée selon la situation. La clé de la gestion des exceptions est de les intercepter uniquement lorsque vous pouvez y remédier. Les attraper et renvoyer une valeur numérique à la fonction appelante est généralement une mauvaise conception. Vous voulez juste les laisser flotter jusqu'à ce que vous puissiez récupérer.
Je considère toujours la gestion des exceptions comme une étape loin de ma logique d'application. Je me demande, si cette exception est levée à quelle distance sauvegarder la pile d'appels dois-je explorer avant que mon application ne soit dans un état récupérable? Dans de nombreux cas, s'il n'y a rien que je puisse faire dans l'application pour récupérer, cela peut signifier que je ne l'attrape pas jusqu'au niveau supérieur et que je journalise l'exception, échoue le travail et essaie de m'arrêter proprement.
Il n'y a vraiment pas de règle stricte pour déterminer quand et comment configurer la gestion des exceptions, sauf les laisser seuls jusqu'à ce que vous sachiez quoi en faire.
la source
Les exceptions sont de belles choses. Ils vous permettent de produire une description claire d'un problème d'exécution sans recourir à une ambiguïté inutile. Les exceptions peuvent être typées, sous-typées et peuvent être gérées par type. Ils peuvent être transmis pour être manipulés ailleurs, et s'ils ne peuvent pas être manipulés, ils peuvent être surélevés pour être traités à une couche supérieure de votre application. Ils reviendront également automatiquement de votre méthode sans avoir à invoquer beaucoup de logique folle pour gérer les codes d'erreur obscurcis.
Vous devez lever une exception immédiatement après avoir rencontré des données non valides dans votre code. Vous devez encapsuler les appels à d'autres méthodes dans un try..catch..finalement pour gérer toutes les exceptions qui pourraient être levées, et si vous ne savez pas comment répondre à une exception donnée, vous la lancez à nouveau pour indiquer aux couches supérieures que il y a quelque chose de mal qui devrait être traité ailleurs.
La gestion des codes d'erreur peut être très difficile. Vous vous retrouvez généralement avec beaucoup de duplication inutile dans votre code et / ou beaucoup de logique désordonnée pour gérer les états d'erreur. Être un utilisateur et rencontrer un code d'erreur est encore pire, car le code lui-même ne sera pas significatif et ne fournira pas à l'utilisateur un contexte pour l'erreur. Une exception, d'autre part, peut indiquer à l'utilisateur quelque chose d'utile, comme "Vous avez oublié de saisir une valeur", ou "vous avez entré une valeur non valide, voici la plage valide que vous pouvez utiliser ...", ou "Je ne sais pas savoir ce qui s'est passé, contactez le support technique et dites-leur que je viens de planter et donnez-leur la trace de pile suivante ... ".
Donc, ma question au PO est la suivante: pourquoi diable ne voudriez-vous pas utiliser des exceptions par rapport aux codes d'erreur renvoyés?
la source
Toutes les bonnes réponses. Je voudrais également ajouter que le retour d'un code d'erreur au lieu de lever une exception peut compliquer le code de l'appelant. Dire que la méthode A appelle la méthode B appelle la méthode C et C rencontre une erreur. Si C renvoie un code d'erreur, B doit maintenant avoir une logique pour déterminer s'il peut gérer ce code d'erreur. S'il ne le peut pas, il doit le renvoyer à A. Si A ne peut pas gérer l'erreur, que faites-vous? Jetez une exception? Dans cet exemple, le code est beaucoup plus propre si C lève simplement une exception, B n'attrape pas l'exception donc il abandonne automatiquement sans qu'aucun code supplémentaire ne soit nécessaire pour le faire et A peut intercepter certains types d'exceptions tout en laissant les autres continuer l'appel empiler.
Cela rappelle une bonne règle à coder en:
la source
J'ai utilisé une combinaison des deux solutions: pour chaque fonction de validation, je passe un enregistrement que je remplis avec le statut de validation (un code d'erreur). À la fin de la fonction, si une erreur de validation existe, je lève une exception, de cette façon je ne lève pas d'exception pour chaque champ, mais une seule fois.
J'ai également profité du fait que lever une exception arrêterait l'exécution car je ne souhaite pas que l'exécution se poursuive lorsque les données ne sont pas valides.
Par exemple
Si vous vous basez uniquement sur le booléen, le développeur qui utilise ma fonction devrait en tenir compte en écrivant:
mais il peut oublier et appeler seulement
Validate()
(je sais qu'il ne devrait pas, mais peut-être qu'il pourrait).Ainsi, dans le code ci-dessus, j'ai gagné les deux avantages:
la source
Il n'y a pas une seule réponse ici - un peu comme il n'y a pas une sorte d'exception HttpException.
Il est très logique que les bibliothèques HTTP sous-jacentes lèvent une exception lorsqu'elles obtiennent une réponse 4xx ou 5xx; la dernière fois que j'ai regardé les spécifications HTTP, c'étaient des erreurs.
Quant à lever cette exception - ou à l'envelopper et à la relancer - je pense que c'est vraiment une question de cas d'utilisation. Par exemple, si vous écrivez un wrapper pour récupérer des données de l'API et les exposer à des applications, vous pouvez décider que sémantiquement une demande de ressource inexistante qui renvoie un HTTP 404 aurait plus de sens pour l'attraper et retourner null. D'un autre côté, une erreur 406 (non acceptable) pourrait valoir la peine de renvoyer une erreur car cela signifie que quelque chose a changé et que l'application devrait planter et brûler et crier à l'aide.
la source