Je suis tombé sur cette page MSDN qui déclare:
Ne lancez pas Exception , SystemException , NullReferenceException ou IndexOutOfRangeException intentionnellement à partir de votre propre code source.
Malheureusement, cela ne prend pas la peine d'expliquer pourquoi. Je peux deviner les raisons, mais j'espère que quelqu'un de plus autoritaire sur le sujet pourrait offrir son point de vue.
Les deux premiers ont un sens évident, mais les deux derniers semblent être ceux que vous voudriez utiliser (et en fait, je l'ai).
De plus, s'agit-il des seules exceptions à éviter? S'il y en a d'autres, quels sont-ils et pourquoi devraient-ils également être évités?
c#
exception-handling
DonBoitnott
la source
la source
NullArgumentException
laquelle certaines personnes pourraient confondre les deux.ApplicationException
Réponses:
Exception
est le type de base pour toutes les exceptions, et en tant que tel terriblement non spécifique. Vous ne devriez jamais lever cette exception car elle ne contient tout simplement aucune information utile. L'appel de code capturant des exceptions ne pouvait pas lever l'ambiguïté de l'exception intentionnellement levée (de votre logique) à partir d'autres exceptions système qui sont totalement indésirables et signalent de véritables erreurs.La même raison s'applique également à
SystemException
. Si vous regardez la liste des types dérivés, vous pouvez voir un grand nombre d'autres exceptions avec une sémantique très différente.NullReferenceException
etIndexOutOfRangeException
sont d'une nature différente. Maintenant, ce sont des exceptions très spécifiques, donc les lancer pourrait être bien. Cependant, vous ne voudrez toujours pas les lancer, car ils signifient généralement qu'il y a de réelles erreurs dans votre logique. Par exemple, l'exception de référence nulle signifie que vous essayez d'accéder à un membre d'un objet qui estnull
. Si c'est une possibilité dans votre code, vous devriez toujours vérifier explicitementnull
et lancer une exception plus utile à la place (par exempleArgumentNullException
). De même, lesIndexOutOfRangeException
s se produisent lorsque vous accédez à un index non valide (sur des tableaux et non sur des listes). Vous devez toujours vous assurer de ne pas faire cela en premier lieu et vérifier d'abord les limites d'un tableau, par exemple.Il existe quelques autres exceptions comme celles-ci, par exemple
InvalidCastException
ouDivideByZeroException
, qui sont lancées pour des erreurs spécifiques dans votre code et signifient généralement que vous faites quelque chose de mal ou que vous ne vérifiez pas d'abord certaines valeurs non valides. En les jetant sciemment à partir de votre code, vous rendez simplement plus difficile pour le code appelant de déterminer s'ils ont été lancés en raison d'une erreur dans le code, ou simplement parce que vous avez décidé de les réutiliser pour quelque chose dans votre implémentation.Bien sûr, il existe quelques exceptions (hah) à ces règles. Si vous créez quelque chose qui peut provoquer une exception qui correspond exactement à une exception existante, n'hésitez pas à l'utiliser, en particulier si vous essayez de faire correspondre un comportement intégré. Assurez-vous simplement de choisir un type d'exception très spécifique.
En général cependant, à moins que vous ne trouviez une exception (spécifique) qui répond à vos besoins, vous devriez toujours envisager de créer vos propres types d'exceptions pour des exceptions attendues spécifiques. Surtout lorsque vous écrivez du code de bibliothèque, cela peut être très utile pour séparer les sources d'exceptions.
la source
IList
implémentation, ce n'est pas en votre pouvoir d'affecter les indices demandés, c'est l' erreur de logique de l'appelant lorsqu'un index est invalide, et vous ne pouvez que les informer de cette erreur logique en lançant une exception appropriée. Pourquoi n'estIndexOutOfRangeException
pas approprié?IList
, alors vous lancerez unArgumentOutOfRangeException
comme le suggère la documentation de l' interface .IndexOutOfRangeException
est pour les tableaux, et pour autant que je sache, vous ne pouvez pas réimplémenter les tableaux.NullReferenceException
est généralement jeté en interne comme un cas spécial deAccessViolationException
(IIRC, le test est quelque chose commecmp [addr], addr
, c'est-à-dire qu'il essaie de déréférencer le pointeur et s'il échoue avec une violation d'accès, il gère la différence entre NRE et AVE dans le gestionnaire d'interruption résultant). Donc, à part des raisons sémantiques, il y a aussi de la triche. Cela peut également vous décourager de vérifiernull
manuellement lorsque cela ne sert à rien - si vous voulez quand même lancer un NRE, pourquoi ne pas laisser .NET le faire?Je soupçonne que l'intention avec les 2 derniers est d'éviter la confusion avec des exceptions intégrées qui ont une signification attendue. Cependant, je suis d'avis que si vous préservez l'intention exacte de l'exception : c'est la bonne
throw
. Par exemple, si vous écrivez une collection personnalisée, il semble tout à fait raisonnable de l'utiliserIndexOutOfRangeException
- plus clair et plus spécifique, IMO, queArgumentOutOfRangeException
. Et bien que vousList<T>
puissiez choisir ce dernier, il y a au moins 41 endroits (gracieuseté du réflecteur) dans la BCL (sans compter les tableaux) qui jettent sur mesure est un peu utile dans les méthodes d'extension - si vous voulez préserver la sémantique que:IndexOutOfRangeException
- dont aucun n'est suffisamment "bas" pour mériter une exemption spéciale. Alors oui, je pense que vous pouvez à juste titre soutenir que cette directive est idiote. Également,NullReferenceException
jette un
NullReferenceException
quandobj
estnull
.la source
SomeMethod()
n'est pas nécessaire d'effectuer un accès membre, il est incorrect de le forcer. De même: reprenez ce point avec les 41 endroits dans la BCL qui créent la personnalisationIndexOutOfRangeException
et les 16 endroits qui créent la personnalisationNullReferenceException
ArgumentNullException
lieu d'unNullReferenceException
. Même si le sucre syntaxique des méthodes d'extension autorise la même syntaxe que l'accès normal aux membres, cela fonctionne toujours très différemment. Et obtenir un NREMyStaticHelpers.SomeMethod(obj)
serait tout simplement faux.Comme vous le faites remarquer, dans l'article Créer et lancer des exceptions (Guide de programmation C #) sous la rubrique Choses à éviter lors de la levée d'exceptions , Microsoft répertorie en effet
System.IndexOutOfRangeException
comme un type d'exception qui ne doit pas être levé intentionnellement à partir de votre propre code source.En revanche, dans l'article throw (référence C #) , Microsoft semble enfreindre ses propres directives. Voici une méthode que Microsoft a incluse dans son exemple:
Donc, Microsoft lui-même n'est pas cohérent car il démontre le lancement de
IndexOutOfRangeException
dans sa documentation pourthrow
!Cela me porte à croire qu'au moins pour le cas de
IndexOutOfRangeException
, il peut y avoir des occasions où ce type d'exception peut être levé par le programmeur et être considéré comme une pratique acceptable.la source
Quand j'ai lu votre question, je me suis demandé dans quelles conditions on voudrait lever les types d'exceptions
NullReferenceException
,InvalidCastException
ouArgumentOutOfRangeException
.À mon avis, lorsque je rencontre l'un de ces types d'exceptions, je (le développeur) me sens concerné par l'avertissement dans le sens où le compilateur me parle. Donc, vous permettre (le développeur) de lancer de tels types d'exception équivaut à (le compilateur) vendre la responsabilité. Par exemple, cela suggère que le compilateur devrait maintenant permettre au développeur de décider si un objet l'est
null
. Mais faire une telle détermination devrait vraiment être le travail du compilateur.PS: Depuis 2003, je développe mes propres exceptions pour pouvoir les lancer comme je le souhaite. Je pense que cela est considéré comme une pratique exemplaire.
la source
Mettre la discussion sur
NullReferenceException
et deIndexOutOfBoundsException
côté:Qu'en est-il de la capture et du lancer
System.Exception
. J'ai beaucoup jeté ce type d'exception dans mon code et je n'ai jamais été foutu par cela. De même, très souvent, j'attrape leException
type non spécifique , et cela a également très bien fonctionné pour moi. Alors, pourquoi est-ce?Habituellement, les utilisateurs soutiennent qu'ils devraient être capables de distinguer les causes d'erreur. D'après mon expérience, il existe très peu de situations dans lesquelles vous souhaiteriez gérer différents types d'exceptions différemment. Dans les cas où vous vous attendez à ce que les utilisateurs gèrent les erreurs par programme, vous devez lever un type d'exception plus spécifique. Pour les autres cas, je ne suis pas convaincu par le guide général des meilleures pratiques.
Donc, en ce qui concerne le lancer,
Exception
je ne vois pas de raison d'interdire cela dans tous les cas.EDIT: également à partir de la page MSDN:
L'exagération des clauses catch avec une logique individuelle pour différents types d'exceptions n'est pas non plus une bonne pratique.
la source