J'ai lu de nombreux articles (et quelques autres questions similaires qui ont été publiées sur StackOverflow) sur la manière et le moment d'utiliser les assertions, et je les ai bien comprises. Mais encore, je ne comprends pas quel genre de motivation devrait me pousser à utiliser Debug.Assert
au lieu de lancer une simple exception. Ce que je veux dire, c'est que dans .NET, la réponse par défaut à une assertion échouée est «d'arrêter le monde» et d'afficher une boîte de message à l'utilisateur. Bien que ce type de comportement puisse être modifié, je trouve cela très ennuyeux et redondant de le faire, alors que je pourrais plutôt lancer une exception appropriée. De cette façon, je pourrais facilement écrire l'erreur dans le journal de l'application juste avant de lancer l'exception, et de plus, mon application ne se fige pas nécessairement.
Alors, pourquoi devrais-je, le cas échéant, utiliser Debug.Assert
au lieu d'une simple exception? Placer une assertion là où elle ne devrait pas être pourrait simplement provoquer toutes sortes de "comportements indésirables", donc à mon avis, je ne gagne vraiment rien en utilisant une assertion au lieu de lancer une exception. Êtes-vous d'accord avec moi ou est-ce que je manque quelque chose ici?
Remarque: Je comprends parfaitement quelle est la différence "en théorie" (Debug vs Release, modèles d'utilisation, etc.), mais comme je le vois, je ferais mieux de lancer une exception au lieu d'effectuer une assertion. Puisque si un bogue est découvert sur une version de production, je voudrais toujours que "l'assertion" échoue (après tout, le "surcoût" est ridiculement petit), donc je ferai mieux de lancer une exception à la place.
Edit: La façon dont je le vois, si une assertion échoue, cela signifie que l'application est entrée dans une sorte d'état corrompu et inattendu. Alors pourquoi voudrais-je continuer l'exécution? Peu importe si l'application s'exécute sur une version de débogage ou de publication. La même chose vaut pour les deux
la source
Réponses:
Bien que je convienne que votre raisonnement est plausible - c'est-à-dire que si une affirmation est violée de manière inattendue, il est logique d'arrêter l'exécution en lançant - je n'utiliserais personnellement pas d'exceptions à la place des affirmations. Voici pourquoi:
Comme d'autres l'ont dit, les affirmations devraient documenter des situations qui sont impossibles , de telle manière que si la situation prétendument impossible se produit, le développeur en est informé. Les exceptions, en revanche, fournissent un mécanisme de contrôle du flux pour les situations exceptionnelles, improbables ou erronées, mais pas les situations impossibles. Pour moi, la principale différence est la suivante:
Il devrait TOUJOURS être possible de produire un cas de test qui exerce une instruction throw donnée. S'il n'est pas possible de produire un tel cas de test, alors vous avez un chemin de code dans votre programme qui ne s'exécute jamais, et il doit être supprimé en tant que code mort.
Il ne devrait JAMAIS être possible de produire un cas de test qui déclenche une assertion. Si une assertion se déclenche, soit le code est erroné, soit l'assertion est fausse; de toute façon, quelque chose doit changer dans le code.
C'est pourquoi je ne remplacerais pas une assertion par une exception. Si l'assertion ne peut pas réellement se déclencher, la remplacer par une exception signifie que vous avez un chemin de code non testable dans votre programme . Je n'aime pas les chemins de code non testables.
la source
Les assertions sont utilisées pour vérifier la compréhension du monde par le programmeur. Une assertion ne doit échouer que si le programmeur a fait quelque chose de mal. Par exemple, n'utilisez jamais une assertion pour vérifier l'entrée utilisateur.
Teste les conditions qui "ne peuvent pas arriver". Les exceptions concernent les conditions qui "ne devraient pas se produire mais se produisent".
Les assertions sont utiles car au moment de la construction (ou même au moment de l'exécution), vous pouvez modifier leur comportement. Par exemple, souvent dans les versions de version, les assertions ne sont même pas vérifiées, car elles introduisent une surcharge inutile. Il faut également se méfier de cela: vos tests peuvent même ne pas être exécutés.
Si vous utilisez des exceptions au lieu d'assertions, vous perdez de la valeur:
Le code est plus détaillé, car tester et lancer une exception fait au moins deux lignes, tandis qu'une assert n'en est qu'une.
Votre code de test et de lancement sera toujours exécuté, tandis que les assertions peuvent être compilées.
Vous perdez une certaine communication avec les autres développeurs, car les assertions ont une signification différente de celle du code produit qui vérifie et lance. Si vous testez vraiment une assertion de programmation, utilisez une assert.
Plus ici: http://nedbatchelder.com/text/assert.html
la source
EDIT: En réponse à la modification / note que vous avez faite dans votre message: Il semble que l'utilisation d'exceptions soit la bonne chose à utiliser plutôt que d'utiliser des assertions pour le type de choses que vous essayez d'accomplir. Je pense que la pierre d'achoppement mentale que vous rencontrez est que vous envisagez des exceptions et des affirmations pour atteindre le même objectif, et vous essayez donc de déterminer laquelle serait «bonne» à utiliser. Bien qu'il puisse y avoir un certain chevauchement dans la façon dont les assertions et les exceptions peuvent être utilisées, ne confondez pas cela car elles sont des solutions différentes au même problème - elles ne le sont pas. Les affirmations et les exceptions ont chacune leur but, leurs forces et leurs faiblesses.
J'allais taper une réponse dans mes propres mots mais cela rend le concept plus juste que je ne l'aurais fait:
Station C #: Assertions
Fondamentalement, utilisez des exceptions pour les choses qui doivent être interceptées / traitées dans une application de production, utilisez des assertions pour effectuer des vérifications logiques qui seront utiles pour le développement mais désactivées en production.
la source
Je pense qu'un exemple pratique (artificiel) peut aider à éclairer la différence:
(adapté de l'extension Batch de MoreLinq )
Donc, comme Eric Lippert et al l'ont dit, vous n'affirmez que des choses que vous vous attendez à être correctes, juste au cas où vous (le développeur) l' auriez mal utilisé ailleurs, afin que vous puissiez corriger votre code. Vous lancez essentiellement des exceptions lorsque vous n'avez aucun contrôle sur ou ne pouvez pas anticiper ce qui arrive, par exemple pour l'entrée de l'utilisateur , de sorte que tout ce qui lui a donné de mauvaises données puisse répondre de manière appropriée (par exemple l'utilisateur).
la source
Un autre pépite de Code Complete :
Il ajoute quelques lignes directrices sur ce qui devrait et ne devrait pas être affirmé.
En revanche, les exceptions:
Si vous n'avez pas ce livre, vous devriez l'acheter.
la source
Debug.Assert par défaut ne fonctionnera que dans les versions de débogage, donc si vous voulez détecter tout type de mauvais comportement inattendu dans vos versions de version, vous devrez utiliser des exceptions ou activer la constante de débogage dans les propriétés de votre projet (ce qui est pris en compte dans général de ne pas être une bonne idée).
la source
Utilisez des assertions pour des choses qui SONT possibles mais qui ne devraient pas arriver (si c'était impossible, pourquoi mettriez-vous une assertion?).
Cela ne ressemble-t-il pas à un cas à utiliser
Exception
? Pourquoi utiliseriez-vous une assertion au lieu d'unException
?Parce qu'il devrait y avoir du code qui est appelé avant votre assertion qui empêcherait le paramètre de l'assertion d'être faux.
Habituellement, il n'y a pas de code avant votre
Exception
qui garantit qu'il ne sera pas lancé.Pourquoi est-ce bon qui
Debug.Assert()
est compilé en prod? Si vous voulez en savoir plus sur le débogage, ne voudriez-vous pas le savoir en prod?Vous ne le souhaitez que pendant le développement, car une fois que vous trouvez des
Debug.Assert(false)
situations, vous écrivez du code pour garantir queDebug.Assert(false)
cela ne se reproduira plus. Une fois le développement terminé, en supposant que vous ayez trouvé lesDebug.Assert(false)
situations et les avoir corrigées, leDebug.Assert()
peut être compilé en toute sécurité car ils sont maintenant redondants.la source
Supposons que vous soyez membre d'une équipe assez importante et que plusieurs personnes travaillent toutes sur la même base de code générale, y compris le chevauchement sur les classes. Vous pouvez créer une méthode qui est appelée par plusieurs autres méthodes et pour éviter les conflits de verrouillage, vous ne lui ajoutez pas de verrou séparé, mais "supposez" qu'elle a été précédemment verrouillée par la méthode appelante avec un verrou spécifique. Tels que, Debug.Assert (RepositoryLock.IsReadLockHeld || RepositoryLock.IsWriteLockHeld); Les autres développeurs peuvent ignorer un commentaire indiquant que la méthode appelante doit utiliser le verrou, mais ils ne peuvent pas l'ignorer.
la source