Je suis généralement d'accord avec la plupart des avertissements d'analyse de code et j'essaie de les respecter. Cependant, j'ai plus de difficultés avec celui-ci:
CA1031: Ne pas intercepter les types d'exception générale
Je comprends la raison d'être de cette règle. Mais, dans la pratique, si je veux faire la même chose, quelle que soit l'exception levée, pourquoi devrais-je traiter chacune d'elles spécifiquement? De plus, si je gère des exceptions spécifiques, que se passe-t-il si le code que j'appelle change pour générer une nouvelle exception à l'avenir? Maintenant, je dois changer de code pour gérer cette nouvelle exception. Considérant que si je attrape simplement Exception
mon code ne doit pas changer.
Par exemple, si Foo appelle Bar et que Foo doit arrêter le traitement quel que soit le type d'exception levée par Bar, y a-t-il un avantage à préciser le type d'exception que je intercepte?
Peut-être un meilleur exemple:
public void Foo()
{
// Some logic here.
LogUtility.Log("some message");
}
public static void Log()
{
try
{
// Actual logging here.
}
catch (Exception ex)
{
// Eat it. Logging failures shouldn't stop us from processing.
}
}
Si vous ne capturez pas une exception générale ici, vous devez capturer tous les types d'exceptions possibles. Patrick a un bon point qui OutOfMemoryException
ne devrait pas être traité de cette façon. Alors que faire si je veux ignorer toutes les exceptions sauf OutOfMemoryException
?
la source
OutOfMemoryException
? Même code de manipulation que tout le reste?OutOfMemoryError
, qui est séparé de l'Exception
arbre d'héritage pour cette raison mêmeRéponses:
Ces règles sont généralement une bonne idée et doivent donc être suivies.
Mais rappelez-vous que ce sont des règles génériques. Ils ne couvrent pas toutes les situations. Ils couvrent les situations les plus courantes. Si vous avez une situation spécifique et que vous pouvez argumenter que votre technique est meilleure (et que vous devriez être capable d'écrire un commentaire dans le code pour articuler votre argument), faites-le (puis faites-le examiner par des pairs).
Sur le contre de l'argument.
Je ne vois pas votre exemple ci-dessus comme une bonne situation pour le faire. Si le système de journalisation échoue (probablement en enregistrant une autre exception), je ne souhaite probablement pas que l'application continue. Quittez et imprimez l'exception sur la sortie afin que l'utilisateur puisse voir ce qui s'est passé.
la source
Oui, attraper des exceptions générales est une mauvaise chose. Une exception signifie généralement que le programme ne peut pas faire ce que vous lui avez demandé de faire.
Vous pouvez gérer quelques types d’exceptions :
Oh, et en règle générale: si vous ne savez pas quoi faire avec une exception si vous l'attrapez, il est préférable d'échouer rapidement (transmettez l'exception à l'appelant et laissez-la s'en occuper)
la source
La boucle externe la plus haute devrait en avoir un pour imprimer tout ce qu'elle peut, puis mourir d'une mort horrible, violente et NOISY (car cela ne devrait pas se produire et quelqu'un doit l'entendre).
Sinon, vous devez généralement être très prudent, car vous n'avez probablement pas anticipé tout ce qui pourrait se produire à cet endroit, et vous ne le traiterez donc probablement pas correctement. Soyez aussi précis que possible afin que vous ne surprenez ceux que vous savez qui va se passer, et que ceux pas vu avant la bulle jusqu'à la mort bruyante mentionnée ci - dessus.
la source
Ce n'est pas que c'est mauvais, c'est juste que les captures spécifiques sont meilleures. Lorsque vous êtes spécifique, cela signifie que vous comprenez réellement, de manière plus concrète, ce que fait votre application et que vous en avez plus le contrôle. En général, si vous rencontrez une situation dans laquelle vous attrapez une exception, enregistrez-la et continuez, il y a probablement de mauvaises choses qui se passent de toute façon. Si vous attrapez spécifiquement les exceptions que vous savez qu'un bloc de code ou une méthode peut générer, il est plus probable que vous puissiez réellement récupérer au lieu de simplement vous connecter et espérer le meilleur.
la source
Les deux possibilités ne sont pas mutuellement exclusives.
Dans une situation idéale, vous intercepteriez tous les types d'exceptions possibles que votre méthode pourrait générer, les traiter sur une base d'exception et à la fin, ajouter une
catch
clause générale pour intercepter toute exception future ou inconnue. De cette façon, vous obtenez le meilleur des deux mondes.Gardez à l'esprit que pour capturer les exceptions plus spécifiques, vous devez les définir en premier.
Edit: Pour les raisons indiquées dans les commentaires, ajouté une relance dans la dernière capture.
la source
Je réfléchissais récemment à la même chose, et ma conclusion provisoire est que la simple question se pose parce que la hiérarchie des exceptions .NET est gravement perturbée.
Prenez, par exemple, humble
ArgumentNullException
qui pourrait être un candidat raisonnable pour une exception que vous ne voulez pas intercepter, car il a tendance à indiquer un bogue dans le code plutôt qu'une erreur d'exécution légitime. Ah oui. Il en va de mêmeNullReferenceException
, sauf queNullReferenceException
cela découleSystemException
directement, de sorte qu'il n'y a pas de compartiment dans lequel vous pouvez placer toutes les "erreurs logiques" pour intercepter (ou ne pas intercepter).Ensuite, il y a le gros problème d'IMNSHO deQuand vous obtenez unSEHException
dériver (viaExternalException
)SystemException
et donc d'en faire un "normal".SystemException
SEHException
, vous voulez écrire un dump et terminer aussi vite que vous le pouvez - et en commençant par .NET 4 au moins certains Les exceptions SEH sont considérées comme des exceptions d'état corrompues qui ne seront pas interceptées. Une bonne chose, et un fait qui rend laCA1031
règle encore plus inutile, car à présent, vos paresseuxcatch (Exception)
ne pourront plus attraper ces pires types.Ensuite, il semble que les autres éléments du cadre dérivent de manière plutôt incohérente, soit
Exception
directement, soit viaSystemException
, en essayant de regrouper les clauses de capture par quelque chose comme une gravité sans importance.M. Lippert
C#
, célèbre artiste , a écrit un article intitulé Vexing Exception , dans lequel il présente une catégorisation utile des exceptions: vous pouvez affirmer que vous souhaitez uniquement capturer les applications "exogènes", sauf que ...C#
le langage et la conception du .NET les exceptions-cadres empêchent de "capturer uniquement les espèces exogènes" de manière succincte. (et, par exemple, anOutOfMemoryException
peut très bien être une erreur récupérable totalement normale pour une API qui doit allouer des mémoires tampons qui sont en quelque sorte grandes)En conclusion, pour moi, la manière dont fonctionnent
C#
les blocs catch et la structure de la hiérarchie des exceptions du FrameworkCA1031
est totalement inutile . Il prétend aider à résoudre le problème fondamental de "ne pas avaler les exceptions", mais avaler des exceptions n'a rien à voir avec ce que vous attrapez, mais avec ce que vous faites ensuite :Il y a au moins 4 façons de gérer légitimement un pris
Exception
etCA1031
semble ne maîtriser que superficiellement l'un d'entre eux (à savoir le cas de relance).Par ailleurs, il existe une fonctionnalité C # 6 appelée Filtres d’exception qui rendra un
CA1031
peu plus valide car vous pourrez alors filtrer correctement les exceptions que vous souhaitez intercepter, et il n’existera aucune raison de rédiger un filtre non filtrécatch (Exception)
.la source
OutOfMemoryException
est qu’il n’existe pas de code permettant d’être sûr que cela indique "seulement" l’échec d’une allocation particulière que l’on était prêt à faire échouer. Il est possible qu'une autre exception plus grave ait été levée et qu'elle se soitOutOfMemoryException
produite pendant le déroulement de la pile à partir de cette autre exception. Java a peut-être été en retard pour la partie avec ses "try-with-resources", mais il gère les exceptions lors du déroulement de la pile un peu mieux que .NET.finally
blocs contre les exceptions auxquelles on peut raisonnablement s'attendre de manière à ce que les exceptions d'origine et nouvelles soient toutes deux consignées. Malheureusement, cela nécessitera souvent une allocation de mémoire, ce qui pourrait entraîner des échecs.La gestion des exceptions Pokemon (il faut les attraper tous!) N’est certainement pas toujours mauvaise. Lorsque vous exposez une méthode à un client, en particulier à un utilisateur final, il est souvent préférable de tout capturer plutôt que de faire planter et graver votre application.
Généralement, ils doivent être évités autant que possible. À moins que vous ne puissiez prendre des mesures spécifiques en fonction du type de l'exception, il est préférable de ne pas la gérer et de permettre à l'exception de bouillonner plutôt que d'avaler l'exception ou de la gérer de manière incorrecte.
Jetez un oeil à cette réponse pour plus de lecture.
la source
LoadDocument()
celle-ci, il est essentiellement impossible d'identifier tout ce qui pourrait mal tourner, mais 99% des exceptions pouvant être levées signifient simplement "Il n'était pas possible d'interpréter le contenu d'un fichier portant le même nom. un document; en traiter. " Si quelqu'un tente d'ouvrir quelque chose qui n'est pas un fichier de document valide, cela ne devrait pas bloquer l'application et tuer tous les autres documents ouverts. La gestion des erreurs Pokemon dans de tels cas est laide, mais je ne connais pas de bonne alternative.La capture d'une exception générale est incorrecte car elle laisse votre programme dans un état non défini. Vous ne savez pas où les choses ont mal tourné, vous ne savez donc pas ce que votre programme a réellement fait ou n'a pas fait.
Là où j'autoriserais tout, c'est lors de la fermeture d'un programme. Tant que vous pouvez le nettoyer bien. Rien de plus agaçant qu'un programme que vous fermez ne lance qu'une boîte de dialogue d'erreur qui ne fait que rester assis à la place, ne disparaissant pas et empêchant votre ordinateur de fermer.
Dans un environnement distribué, votre méthode de journalisation pourrait se retourner contre vous: si une exception générale était capturée, votre programme aurait toujours un verrou sur le fichier journal empêchant les autres utilisateurs de créer des journaux.
la source
Comme d’autres l’ont dit, il est très difficile (voire impossible) d’imaginer une action que vous voudriez entreprendre quelle que soit l’exception levée. Un exemple parmi d'autres sont les situations dans lesquelles l'état du programme a été corrompu et tout traitement ultérieur peut entraîner des problèmes (c'est la raison derrière
Environment.FailFast
).Pour le code de passe-temps, il est tout à fait acceptable
Exception
, mais pour le code de qualité professionnelle, l'introduction d'un nouveau type d'exception doit être traitée avec le même respect qu'un changement dans la signature de la méthode, c'est-à-dire être considérée comme un changement radical. Si vous vous abonnez à ce point de vue, il est immédiatement évident que revenir au code client (ou à le vérifier) est la seule solution correcte.Bien sûr, parce que vous ne capturerez pas que des exceptions
Bar
. Il y aura également des exceptions que les clients de Bar ou même le moteur d'exécution peuvent émettre pendant la durée de laBar
pile d'appels. Un utilisateur bien écritBar
doit définir son propre type d'exception si nécessaire afin que les appelants puissent spécifiquement intercepter les exceptions émises par lui-même.IMHO c'est la mauvaise façon de penser à la gestion des exceptions. Vous devriez opérer sur des listes blanches (intercepter les types d'exceptions A et B) et non sur des listes noires (intercepter toutes les exceptions sauf X).
la source
Peut - être . Il existe des exceptions à chaque règle et aucune règle ne doit être suivie sans discernement. Vous pouvez, par exemple , constituer l’un des cas où il est logique d’avaler toutes les exceptions. Par exemple, si vous souhaitez ajouter un traçage à un système de production critique et que vous voulez vous assurer que vos modifications ne perturbent pas la tâche principale de l'application.
Cependant , vous devez bien réfléchir aux raisons possibles d’un échec avant de décider de les ignorer en silence. Par exemple, que se passe-t-il si la raison de l'exception est:
Ne voulez-vous pas être averti immédiatement de la présence de ce problème afin de pouvoir le résoudre? En avalant l'exception, vous ne saurez jamais que quelque chose s'est mal passé.
Certains problèmes (par exemple, le disque est plein) peuvent également entraîner l'échec d'autres parties de l'application - mais cet échec n'est pas enregistré pour le moment, vous ne savez donc jamais!
la source
J'aimerais aborder cette question d'un point de vue logique plutôt que technique,
Eh bien, il faudrait que quelqu'un s'en occupe. C'est l'idée. Les rédacteurs de code de bibliothèque seraient prudents quant à l'ajout de nouveaux types d'exceptions, mais comme cela risquerait de casser les clients, vous ne devriez pas le rencontrer très souvent.
Votre question est essentiellement "Que faire si je me fiche de ce qui ne va pas? Dois-je vraiment passer par le tracas de découvrir ce que c'était?"
Voici la partie beauté: non vous ne faites pas.
"Alors, est-ce que je peux juste regarder de l'autre côté et faire en sorte que tout ce qui est néfaste soit automatiquement balayé sous le tapis et que ce soit fini?"
Non, ce n'est pas comme ça que ça marche.
Le fait est que la collection d'exceptions possibles est toujours plus volumineuse que la collection que vous attendez et s'intéresse au contexte de votre petit problème local. Vous gérez ceux que vous prévoyez et si quelque chose d'inattendu se produit, vous laissez le soin aux gestionnaires de niveau supérieur plutôt que de l'avaler. Si vous ne vous souciez pas d'une exception à laquelle vous ne vous attendiez pas, vous misez quelqu'un sur la pile d'appels et ce serait un sabotage de tuer une exception avant qu'elle n'atteigne son gestionnaire.
"Mais ... mais ... alors une de ces autres exceptions qui ne me concerne pas pourrait faire échouer ma tâche!"
Oui. Mais ils seront toujours plus importants que ceux gérés localement. Comme une alarme incendie ou le patron qui vous dit d'arrêter ce que vous faites et de relever une tâche plus urgente qui se présentait.
la source
Vous devez intercepter les exceptions générales au plus haut niveau de chaque processus et les gérer en signalant le bogue le mieux possible, puis en mettant fin au processus.
Vous ne devez pas intercepter les exceptions générales et essayer de continuer l'exécution.
la source