Si j'utilise une instruction switch pour gérer les valeurs d'une énumération (qui appartient à ma classe) et que j'ai une casse pour chaque valeur possible - cela vaut-il la peine d'ajouter du code pour gérer le cas «par défaut»?
enum MyEnum
{
MyFoo,
MyBar,
MyBat
}
MyEnum myEnum = GetMyEnum();
switch (myEnum)
{
case MyFoo:
DoFoo();
break;
case MyBar:
DoBar();
break;
case MyBat:
DoBat();
break;
default:
Log("Unexpected value");
throw new ArgumentException()
}
Je ne pense pas que ce soit parce que ce code ne peut jamais être atteint (même avec des tests unitaires). Mon collègue n'est pas d'accord et pense que cela nous protège contre les comportements inattendus causés par l'ajout de nouvelles valeurs à MyEnum.
Que dites-vous, communauté?
unit-testing
maintenance
enum
Dakota du Sud
la source
la source
MyEnum
ensuite la transmettre via votre commutateur?switch
complètement l' instruction.Réponses:
Inclure le cas par défaut ne change pas la façon dont votre code fonctionne, mais il rend votre code plus maintenable. En rendant le code cassé de manière évidente (enregistrez un message et lancez une exception), vous incluez une grosse flèche rouge pour le stagiaire que votre entreprise embauche l'été prochain pour ajouter quelques fonctionnalités. La flèche indique: "Hé, vous! Oui, je vous parle! Si vous voulez ajouter une autre valeur à l'énumération, vous feriez mieux d'ajouter un cas ici aussi." Cet effort supplémentaire pourrait ajouter quelques octets au programme compilé, ce qui est quelque chose à considérer. Mais cela sauvera aussi quelqu'un (peut-être même le futur, vous) entre une heure et une journée de gratte-tête improductif.
Mise à jour: La situation décrite ci-dessus, c'est-à-dire la protection contre les valeurs ajoutées à une énumération ultérieurement, peut également être détectée par le compilateur. Clang (et gcc, je pense) émet par défaut un avertissement si vous activez un type énuméré mais que vous n'avez pas de cas qui couvre toutes les valeurs possibles dans l'énumération. Ainsi, par exemple, si vous supprimez le
default
cas de votre commutateur et ajoutez une nouvelle valeurMyBaz
à l'énumération, vous obtiendrez un avertissement qui dit:Laisser le compilateur détecter les cas non couverts est qu'il élimine largement le besoin de ce
default
cas inaccessible qui a inspiré votre question en premier lieu.la source
J'en parlais également avec un collègue ce matin - c'est vraiment dommage, mais je pense que la gestion du défaut est nécessaire pour la sécurité, pour deux raisons:
Tout d'abord, comme le mentionne votre collègue, il protège le code du futur contre les nouvelles valeurs ajoutées à l'énumération. Cela peut ou non sembler être une possibilité, mais elle est toujours là.
Plus important encore, selon le langage / compilateur, il peut être possible d'avoir des valeurs qui ne sont pas membres de l'énumération dans votre variable commutée. Par exemple, en C #:
En ajoutant le simple
case default:
et en levant une exception, vous vous êtes protégé contre ce cas étrange où "rien" ne se produit mais "quelque chose" aurait dû se produire.Malheureusement, à chaque fois que j'écris une instruction switch, c'est parce que je vérifie les cas d'une énumération. Je souhaite vraiment que le comportement "lancer par défaut" puisse être appliqué par la langue elle-même (au moins en ajoutant un mot-clé).
la source
L'ajout d'un cas par défaut même si vous ne vous attendez jamais à l'atteindre peut être une bonne chose. Cela facilitera le débogage si votre code lève immédiatement une exception «Cela n'aurait pas dû arriver» plutôt que plus tard dans le programme, lançant une exception mystérieuse ou renvoyant des résultats inattendus sans erreur.
la source
Je dis:
Essayez d'ajouter un autre type à
MyEnum
. Modifiez ensuite cette ligne:à
Exécutez ensuite votre code avec le cas par défaut et sans le cas par défaut. Quel comportement préférez-vous?
Avoir le cas par défaut peut également être utile pour intercepter des
NULL
valeurs et les empêcherNullPointerExceptions
.la source
Si vous aviez une idée de la façon de gagner du temps en insistant sur le cas par défaut, vous n'auriez pas besoin de poser la question. Ne rien faire en silence dans une condition d'erreur n'est pas acceptable - détectez-vous en silence des exceptions qui ne devraient jamais se produire? Laisser des "mines" pour les programmeurs qui vous suivent, tout aussi inacceptable.
Si votre code ne sera jamais changé ou modifié, et qu'il est 100% sans bogue, laisser de côté le cas par défaut peut être OK.
Ada (le grand-père des langages de programmation robustes) ne compilera pas de commutateur sur une énumération, à moins que toutes les énumérations soient couvertes ou qu'il y ait un gestionnaire par défaut - cette fonctionnalité est sur ma liste de souhaits pour chaque langue. Notre norme de codage Ada stipule qu'avec les commutateurs sur les énumérations, la gestion explicite de toutes les valeurs, sans valeur par défaut, est la manière préférée de gérer cette situation.
la source