Je suis un peu déchiré entre ces deux modèles de manipulation d'erreurs:
Créer une erreur Boolean Achetez des exceptions dans votre objet et manipulez-les à l'extérieur avec et une chaîne
errorormessage code> Propriété de votre objet. Attrapez toutes les exceptions à l'intérieur des méthodes de l'objet et transmettez les messages à l'aide de la logique conditionnelle à partir de l'appelant, c'est-à-dire: P>
Dim o As New MyObject
Try
o.SomeMethod()
'Do stuff'
Catch ex As Exception
Dim msg As String = ex.ErrorMessage
'do something with message'
End Try
essayer code> logique: p>
Dim o As New MyObject
o.SomeMethod()
If Not o.Error Then
'Do stuff'
Else
Dim msg As String = o.ErrorMessage
'do something with message'
End If
6 Réponses :
Le plus gros problème que j'ai avec le premier est que c'est passif, facilement négligé et non très normalisé. Comment un programmeur peut-il savoir vérifier cette propriété? Ou quelles propriétés / méthodes peuvent définir une erreur? Ou quel accès de propriété / méthode a causé l'erreur d'être définie? p>
Par exemple. Dans votre premier code d'échantillon si O.Error est vrai, il est difficile de savoir si l'initialisation de l'objet ou de l'appel à SOMEMETHOD a entraîné la définition du drapeau. p>
Le modèle d'exception est une façon unignorable de dire à vos utilisateurs qu'une erreur s'est produite. Il ne peut être évité sans code explicite pour gérer la situation. p>
J'ai commencé à mettre en œuvre le deuxième modèle et j'ai compris que beaucoup de manipulation d'erreurs internes peuvent être supprimées, car l'exception peut être traitée à l'extérieur.
Je pense que l'histoire est informative à ce sujet. L'API Win32 utilise des techniques similaires à la première méthode, telles que getlasterror code>, c'est seulement un cauchemar car il n'est pas très standardisé. Cela fait partie de la raison pour laquelle Microsoft a inventé quelque chose appelé .NET et a décidé de manipuler des exceptions structurées tout au long de l'exécution, aucune exception! :)
J'ai décidé d'aller avec des exceptions à la place d'utiliser des codes d'erreur / de retour. Je viens de ressembler vraiment vraiment à ça. p>
La raison n ° 1 de lancer des exceptions est une possibilité que vous pouvez oublier de vérifier le code d'erreur. Si vous ne le vérifiez pas, vous continuerez à fonctionner pendant que l'erreur existe. Avec des exceptions, si vous oubliez de les gérer, l'exception augmentera jusqu'au sommet et arrêtera tout traitement. Il vaut mieux que cela se produise que de continuer après que des erreurs inconnues se produisent. P>
Pour plus d'informations Consultez le chapitre d'exception dans Directives de conception-cadre: Conventions, idiomes et modèles de bibliothèques .NET réutilisables, deuxième édition em> par Addison-Wesley. P>
Joel Spolsky préfère réellement les codes d'erreur / retour sur des exceptions, mais beaucoup de gens sont en désaccord avec lui. Le message de Joel en faveur des codes de retour peut être trouvé ici . Découvrez Ce blog post et tous les commentaires avec une bonne discussion à ce sujet sujet. p>
Préfère # 2. Pour plus de détails, voir cette extrait sur la lancée d'exception de Le développement de l'excellent Directives de conception-cadre , comme Dennis mentionné. Notez notamment la section sur les exceptions et les performances. P>
Version courte: P>
ne renvoie pas les codes d'erreur. P>
signaler les défaillances d'exécution en lançant des exceptions. P>
Ne pas utiliser d'exceptions pour un flux de contrôle normal. P> blockQuote>
Je recommande vivement de lire le livre pour une discussion complète, avec un commentaire à partir de plusieurs luminaires Microsoft. P>
FYI, le livre est disponible sur des livres de safari et est une excellente lecture sur de nombreux objets différents.
Si vous récupérez les directives de conception-cadre (et je le recommande vivement), assurez-vous d'obtenir la deuxième édition.
Les exceptions doivent être utilisées lorsque quelque chose E.g. Vous êtes passé un objet NULL (rien) lorsque vous vous attendez à un. P>
oncle BOB recommande des exceptions sur les codes d'erreur dans son livre Nettoyer Code . P>
il dit p>
Le problème avec ces approches [codes d'erreur] est qu'ils encombrent l'appelant. L'appelant doit vérifier les erreurs immédiatement après l'appel. Malheureusement, il est facile d'oublier. Pour cette raison, il est préférable de jeter une exception lorsque vous rencontrez une erreur. Le code d'appel est plus propre. Sa logique n'est pas masquée par la manipulation des erreurs. P>
blockQuote>
Mais vous n'avez toujours pas à exécuter un essayer de voir code> bloquer quand même? C'est la même chose que la gestion d'une déclaration
si / else code>, non?
Les exceptions ne sont pas pour communiquer des conditions exceptionnelles b> pour communiquer erreur b>. Cela pourrait être une différence subtile, mais c'est un important. Ce qui est exceptionnel pour une application pourrait ne pas être exceptionnel pour un autre. Manipulation des exceptions de référence NULL doit être évitée car elles indiquent presque toujours un bogue dans le code et doivent être fixés dans le code afin qu'ils ne se produisent pas.
@Jason: Qu'est-ce qui finit habituellement par hasard, c'est que plutôt que d'essayer / attraper des blocs, vous utilisez plus d'essais / enfin blocs. N'utilisez pas de gestionnaires de capture pour le nettoyage car ils ne sont pas garantis. Enfin, les blocs vont courir peu importe ce qu'ils doivent contenir votre code de nettoyage. Vous voulez seulement gérer une exception à un moment où vous pouvez réellement faire quelque chose à ce sujet; Sinon, vous devez le laisser baser la pile d'appels. Si vous devez vous connecter à un point inférieur à un point inférieur, assurez-vous d'utiliser simplement le mot-clé code> code> (pas jette ex code>) pour préserver les informations de la trace de la pile.
Ce sont toutes deux des formes de traitement des erreurs acceptées, mais le choix préféré pour les langues .NET est d'utiliser des exceptions. P>
Il y a quelques problèmes avec l'utilisation de codes de retour (numériques ou booléens), les deux plus grands étant: p>
Pour ces raisons seules, vous devriez utiliser des exceptions. Les exceptions fournissent une manière propre et normalisée d'indiquer et de toute défaillance, peu importe où elle se pose. P>
Vous finirez également avec moins de code global car vous ne devez attraper que des exceptions quand et où vous pouvez gérer de manière sûre et de manière appropriée cette exception. P>
Je recommande d'utiliser les deux. p>
"Utilisez le bon outil pour le travail" em> p>
Le "problème" avec les codes de retour est que les gens oublient souvent de les gérer. Cependant, des exceptions ne résolvent pas ce problème! Les gens ne manipulent toujours pas d'exceptions (ils ne réalisent pas une certaine exception doivent être manipulés, ils supposent que quelqu'un de la pile le gérera, sinon ils utilisent une capture () et écrasez toutes les erreurs). P>
Lorsqu'un code de retour non géré peut-être em> signifie que le code est dans un état instable, une exception non gérée souvent garantit em> que le programme va s'écraser. Est-ce mieux? P>
Bien qu'un code de retour est facilement identifiable lors de la rédaction de code, il est souvent impossible (ou juste consommer de manière gagnante) pour déterminer quelles exceptions pourraient être projetées par une méthode que vous appelez. Cela entraîne généralement beaucoup de très mauvaise manipulation d'exception. P>
Les exceptions sont censées être utilisées pour "erreurs". Il y a la difficulté. Si un fichier n'est pas trouvé lorsque vous essayez de l'ouvrir, est-ce une "erreur" ou une "situation attendue"? Seul l'appelant sait. En utilisant des exceptions partout, élève essentiellement chaque information d'état d'état dans une erreur. P>
En fin de compte, la manipulation des erreurs est quelque chose qu'un programmeur doit fonctionner à. Ce problème existe dans les codes de retour et les exceptions. P>
Ainsi, j'utilise des codes de retour pour les informations sur le statut de passage (y compris des "avertissements") et des exceptions pour "erreurs graves". (Et oui, il est parfois difficile de juger de quelle catégorie tombe quelque chose en dessous) p>
exemple cas de .NET: strong> p>
int32.parse jette des exceptions (même si aucune de ses exceptions n'est des erreurs - elle appartient à l'appelant de vérifier les résultats et de décider eux-mêmes si le résultat est valide). Et c'est simplement une douleur (et une performance touchée) de devoir enfermer chaque appel dans un essai / attraper. Et si vous oubliez d'utiliser un try / Catch, un champ de saisie de texte vide simple peut planter votre programme. P>
Ainsi, int32.tryparse () est né. Cela fait la même chose, mais renvoie un code d'erreur au lieu d'une exception, de sorte que vous puissiez simplement ignorer les erreurs (acceptation d'une valeur par défaut de 0 pour toutes les entrées illégales). Dans de nombreuses situations de vie réelles, cela est beaucoup plus propre, plus rapide, plus facile et plus sûr d'utiliser que INT32.PARSE (). P>
"Tryparse" utilise une convention de dénomination pour préciser l'appelant que des erreurs pourraient survenir, cela devrait être correctement traitée. Une autre approche (pour forcer les programmeurs à mieux gérer les erreurs) est de rendre le code de retour dans un paramètre de sortie ou de référence, de sorte que l'appelant soit explicitement informé de la nécessité de gérer les erreurs renvoyées. P>
Les lignes directrices du livre de conception du livret 2nd ed. Donne des lignes directrices sur tout cela, y compris le modèle Tryparse et pour l'utiliser. HAUTEMENT B> Lecture recommandée.
Un problème majeur avec cette approche est que vous avez ensuite deux styles différents et vous pouvez vous retrouver avec beaucoup d'incohérences. Dans votre exemple de raison pour utiliser des codes de retour, si vous vous attendez à ce que un fichier existe lorsque vous allez l'ouvrir et que ce n'est pas là, oui, c'est une exception. Même si vous le conduisez avec un test fichier.exists code>, le fichier ouvert peut toujours échouer car le fichier a été supprimé entre le test de protection et l'ouverture, auquel cas il s'agit toujours d'une exception ...
... "Utiliser des exceptions partout" élève la responsabilité de la manipulation de cette condition d'exception à la couche la plus appropriée i> la couche de code qui puisse faire correctement quelque chose à ce sujet. Oui, int32.Parse CODE> jette des exceptions car peu importe la manière dont vous tranchez, essayez de convertir des données de chaîne non numériques à un entier réel est une erreur.
int32.tryparse code> était "Né" car la conversion de données de chaîne en données numériques est un motif d'interface utilisateur extrêmement courant, le coût de l'exception était trop élevé compte tenu du volume et fait une partie de test bien définie de la méthode. sémantique. Et
int32.trypsarse code> peut encore jeter.
Ce qui vous manque ici, c'est que mon peu de code particulier ne se soucie pas si le fichier existe - dans mon contexte c'est pas i> une erreur. En préjugeant cela et en obligeant une situation quotidienne à traiter comme une erreur, vous introduisez beaucoup de complexité supplémentaire, davantage de code de code et un risque plus élevé dans la situation, sans nécessairement fournir à aucun avantage. L'approche fopen () est que si le fichier peut être ouvert, vous obtenez une poignée de fichier et si elle ne peut pas, vous obtenez une null - ceci est plus facile / moins complexe à gérer, plus efficace et moins sûr d'un exception non-gérée.
Tryparse jette des exceptions pour de véritables erreurs et quitte les "difficultés de validation" comme responsabilité de l'appelant. Cela conduit à un code plus efficace, plus facile à écrire, plus simple et plus propre, qui est un diable de beaucoup plus sûr. (Bien sûr, rien ne vous empêche d'appeler l'analyse dans une situation où les entrées non valides sont i> une erreur. C'est la beauté de l'utilisation du "bon outil pour le travail" au lieu de jeter aveuglément des exceptions chaque fois que vous être nerveux)
(P.S. Je ne préconise pas l'évitement total des exceptions, disant simplement qu'elles devraient être utilisées correctement. Et il y a une grande zone grise entre "devrait être une exception" et "devrait être un résultat de statut")
De votre réponse, "Si un fichier n'est pas trouvé lorsque vous essayez de l'ouvrir, est-ce une" erreur "ou une" situation attendue "? Seul l'appelant sait. B>". C'est exactement la raison pour laquelle les API Ouvrir le fichier dans .NET lancent une exception. fopen () code> retourne
null code> car il n'y a rien d'autre que peut B> retour depuis C n'a pas d'exception. Le problème avec les codes de retour est qu'ils sont très faciles à ignorer, accidentellement ou intentionnellement. Ignorer les exceptions n'est pas aussi simple car elle nécessite toujours un code explicite pour les ignorer ....
... Mélanger les codes d'erreur de retour et les exceptions permettent à plus de code de code et de spaghetti plus de code que d'utiliser des exceptions seules et entraîne un code inconsitent ... Quand dois-je utiliser un code de retour contre une exception?
Ignorer une exception est aussi simple que d'ignorer un code de retour - n'utilisez pas d'essais / attraper. Les codes de retour sont tout autour de vous - une méthode comme 'Bool Haschildren ()' n'utilise généralement pas d'exception pour vous dire que l'objet n'a pas d'enfants - il utilise un code de retour! Mais on pourrait soutenir que peut-être un manque d'enfants sur un nœud est effectivement une erreur. Alors devrait-il jeter une exception si le résultat est "faux"? Bien sûr que non. Faites face, vous mélangez des exceptions et des codes de retour tous les jours. La question lors de la rédaction d'une méthode est la suivante: "Si cet Informaiton sera renvoyé comme une exception ou un code de retour?"