2008-10-13 10 views
9

Quoi qu'il en soit, je suis un peu confus sur le moment de propager une exception et quand l'envelopper, et les différences. Pour l'instant, ma compréhension me dit que l'enroulement d'une exception impliquerait de prendre une exception comme DriveNotFound (dans IO) et de l'encapsuler avec l'exception IOException générale. Mais avec le concept de propagation d'une exception, est-ce seulement quelque chose qui arrive si j'ai une clause catch vide? Ainsi, dans une application Web ASP.NET, il serait propagé à global.asax. Ou dans le cas d'une application web récemment déployée, une HTTPException non gérée a donné un écran de mort jaune et a écrit un journal sur Windows Server (il s'agit d'une application web que je réécris). Ainsi, l'exception se produit dans une méthode, elle peut être traitée au niveau de la classe, affichée dans la page, puis va jusqu'à global.asax ou Windows Server.Pratiques de gestion des exceptions

Pourquoi exactement je veux envelopper une exception avec une exception plus générique? La règle est de gérer une exception avec le type le plus spécifique (donc DriveNotFound pour évidemment un lecteur non trouvé). Aussi, comment choisirais-je entre l'emballage et le remplacement d'une exception?

La chaîne de traitement des exceptions est-elle constituée uniquement des clauses try et catch (ou catch)? Je suppose du libellé, oui.

Enfin, pourquoi et comment voudrais-je laisser une exception se propager dans la pile d'appel? J'ai lu le guide MS PandP sur la gestion des exceptions, mais je suppose que les exemples ne m'ont pas assez engagé pour bien comprendre tout.

Cette question provient de la bibliothèque d'entreprise la possibilité d'envelopper/propager une exception et etc. C'est la propagation dont je ne suis pas sûr, et les différences dans le remplacement/encapsulation d'une exception.

De même, est-ce correct d'insérer une logique de traitement d'erreur complexe dans un bloc catch (par exemple ifs/elses et des choses comme ça).

Merci

Répondre

5

Il est tout au sujet de transmettre le droit sens à vos correspondants. Je doute qu'il y ait une raison d'emballer une exception spécifique dans une exception plus générique - cela n'aide personne. Considérons une API qui n'a rien à voir avec l'accès aux fichiers mais qui accède à un fichier de configuration en arrière-plan. Si le fichier de configuration n'est pas présent, vous pouvez envelopper le FileNotFoundException dans un ConfigurationException afin que le problème correct soit transmis aux appelants.

pourquoi et comment voudrais-je laisser une exception se propage le callstack?

Vous laissez une exception se propager si vous ne pouvez pas la gérer. C'est si simple. Si votre code ne peut ou ne doit rien faire pour contourner l'exception, laissez-le se propager. Lors de la propagation, faites attention comment vous le faites:

throw ex; 

est différent:

throw; 

L'ancien jette l'ancienne trace de la pile et crée une autre du point l'exception est levée. Ce dernier préserve la trace de la pile d'origine.

Bien sûr, si vous ne pouvez pas gérer l'exception, vous ne devriez pas prendre la peine de l'attraper en premier lieu (peut-être que vous voulez vous connecter).

4

que je fais habituellement ceci:

  • ensembles logiques d'affaires (dll) ne gèrent pas les exceptions à moins qu'ils ne soient pleinement comprises
  • Les exceptions qui sont prévus, mais non manipulable sont enveloppé dans un seul type d'exception et sont autorisés à remonter la pile des appels (c.-à-d. toutes les différentes exceptions qui peuvent survenir lors d'une interaction de base de données sont enveloppées dans une seule exception RepositoryException)
  • exceptions inattendues sont autorisés à se propager (jamais inclure une catch(Exception ex) dans une dll)
  • Les exceptions sont traitées seulement au dernier moment (c.-à-contrôleur pour l'interface utilisateur)

Son généralement loin dans l'appel empiler que vous savez exactement ce que vous faites (ce que le processus métier actuel est) et comment gérer correctement les exceptions.

10

Pas moins de 6 questions :-)

Mais avec le concept de propager une exception, est-ce que quelque chose qui se passe si j'ai une clause catch vide?

Une exception se propage vers le haut jusqu'à ce qu'elle soit interceptée par un bloc de capture plus haut dans la pile d'appel qui gère soit ce type de exception spécifique ou un type d'exception plus proche du type de base de la hiérarchie de cette exception. Ainsi, par exemple, toutes les exceptions gérées proviennent de System.Exception, de sorte qu'un bloc catch interceptant System.Exception capture toutes les exceptions gérées.

Pourquoi exactement je veux envelopper une exception avec un plus générique?

Je ne suis pas sûr de ce que vous entendez par « envelopper ». Voulez-vous dire attraper une exception, la remplacer par une autre et ajouter l'original en tant que propriété InnerException de la nouvelle exception? Ou autre chose?

Je pense qu'il y a rarement une bonne raison de remplacer une exception par une exception plus générique. Mais vous pouvez certainement remplacer une exception par une autre exception, pour une ou plusieurs des raisons suivantes:

  • Pour masquer les détails d'implémentation de l'appelant.
  • Pour améliorer le niveau d'une abstraction afin qu'elle soit plus significative pour l'appelant.
  • Pour lancer une exception personnalisée très spécifique au problème en cours.

Aussi, comment pourrais-je choisir entre l'emballage et le remplacement d'une exception?

Je suis désolé, mais je ne comprends toujours pas comment vous définissez ces deux aussi différents.

est la chaîne de gestion des exceptions que la tentative et la capture (ou prises) clauses?

Voici les bases de ce qui se passe quand une exception est levée:

  • Le CLR marche successivement la liste des blocs catch dans le Try local ... Fin bloc Try, à la recherche pour un bloc catch local avec un filtre d'exception correspondant à l'exception lancée.

  • Si un bloc Catch local a un filtre d'exception qui correspond à l'exception exacte qui a été lancée, le code dans ce bloc Catch est exécuté, suivi du code dans le bloc Finally. Ensuite, l'exécution continue à la première déclaration suivant la fin de l'essai.

  • Alternativement, si l'exception qui a été lancée provient de l'exception spécifiée par un bloc Catch local, les mêmes actions se produisent comme décrit dans la deuxième étape. Par exemple, un filtre d'exception qui attrape ArgumentException capture également des exceptions dérivées de ArgumentException, telles que ArgumentNullException, InvalidEnumArgumentException, DuplicateWaitObjectException et ArgumentOutOfRangeException.

  • Si aucun bloc Catch local ne correspond à l'exception lancée, le CLR repasse dans la pile d'appels, méthode par méthode, à la recherche d'un bloc Catch qui souhaite répondre à l'exception. Si aucun bloc Catch correspondant n'est trouvé dans la pile d'appels, l'exception est considérée comme non gérée. En variante, si un bloc Catch correspondant est trouvé quelque part dans la pile d'appels, le code dans chaque bloc Finally entre le lancer et le catch est exécuté. Cela commence par le dernier élément du bloc Try où l'exception a été levée et se termine par la méthode Finally dans la méthode ci-dessous, où l'exception a été interceptée. Une fois ce nettoyage terminé pour toutes les méthodes ci-dessous où l'exception a été interceptée, le contrôle est transféré au bloc Catch qui a intercepté l'exception et ce code est exécuté. Le prochain bloc de l'essai est le suivant où l'exception a été interceptée. Maintenant que la pile d'appels a été déroulée et que le nettoyage des erreurs est terminé, l'étape finale consiste à poursuivre l'exécution à la première déclaration qui suit la fin de l'exécution de l'exception.

  • Si le code d'un bloc Catch provoque la levée d'une autre exception, l'exception d'origine est automatiquement ajoutée à la nouvelle exception à l'aide de la propriété InnerException. De cette manière, les exceptions peuvent être empilées sans aucune perte d'informations.

  • Vous devez éviter de placer du code de nettoyage dans un bloc Finally pouvant générer une exception, à moins que ce code ne se trouve dans son propre bloc Try.Sans cette protection supplémentaire, le CLR se comporte comme si la nouvelle exception avait été lancée après la fin après le bloc Finally et recherchait la pile d'appels pour un bloc Catch distant qui voulait répondre à la nouvelle exception. L'exception d'origine sera perdue sauf si le bloc Catch d'origine l'a enregistré.

Enfin, pourquoi et comment voudrais-je laisser une exception se propage le callstack?

Pourquoi: Chaque fois que vous ne comprenez pas spécifiquement l'exception et de savoir comment récupérer, vous devriez le laisser se propager vers le haut. Comment: En attrapant uniquement les types d'exception que vous comprenez et que vous savez comment gérer. Parfois, vous avez besoin des détails de toute exception afin de faire une bonne récupération. Dans ce cas, vous pouvez l'attraper, faire la récupération, puis le relancer en utilisant le lancer ; déclaration.

Aussi, est-il autorisé à insérer la logique de gestion des erreurs dans un bloc complexe de capture (par exemple ifs/elses et choses de ce genre).

En général oui, car toute nouvelle exception provoquée par le code dans votre bloc Catch aura l'ancienne exception attachée à elle automatiquement via la propriété InnerException. Mais il n'est pas sage de provoquer ce mécanisme si vous pouvez l'éviter, donc le code le plus simple que vous avez, le mieux. Une autre bonne raison de garder votre code Catch simple est qu'il ne subira souvent pas le même degré de test que votre code de ligne principale.

Questions connexes