107 votes

Debug.Assert vs Lancer d'exception

J'ai lu beaucoup de articles (et quelques autres similaire questions qui ont été postées sur StackOverflow) sur comment et quand utiliser les assertions, et je les ai bien comprises. Mais je ne comprends toujours pas quel type de motivation devrait me pousser à utiliser des Debug.Assert au lieu de lever une simple exception. Ce que je veux dire, c'est que dans .NET, la réponse par défaut à l'échec d'une assertion consiste à "arrêter le monde" et à afficher un message à l'utilisateur. Bien que ce type de comportement puisse être modifié, je trouve cela très ennuyeux et redondant. de faire cela, alors que je pourrais, à la place, simplement 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 en plus, mon application ne se fige pas nécessairement.

Alors, pourquoi devrais-je, si tant est que je le fasse, utiliser Debug.Assert au lieu d'une simple exception ? Placer une assertion là où elle ne devrait pas l'être pourrait simplement provoquer toutes sortes de "comportements indésirables", donc de mon point de vue, je ne gagne rien à utiliser une assertion au lieu de lancer une exception. Êtes-vous d'accord avec moi, ou est-ce que quelque chose m'échappe ?

Note : Je comprends parfaitement la différence "en théorie" (Debug vs Release, modèles d'utilisation, etc.), mais à mon avis, il serait préférable de lancer une exception au lieu d'effectuer une assertion. Si un bogue est découvert dans une version de production, je voudrais quand même que l'"assertion" échoue (après tout, l'"overhead" est ridiculement faible), et je ferais donc mieux de lancer une exception à la place.


Edita: De la façon dont je le vois, si une assert é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 que l'application s'exécute sur une version de débogage ou de publication. Il en va de même pour les deux

207voto

Eric Lippert Points 300275

Bien que je sois d'accord que votre raisonnement est plausible -- Je n'utiliserais personnellement pas les exceptions à la place des assertions. Voici pourquoi :

Comme d'autres l'ont dit, les assertions doivent document des situations qui sont impossible de telle sorte que si la situation prétendument impossible se réalise, le développeur en soit informé. Les exceptions, en revanche, fournissent un mécanisme de flux de contrôle pour les situations exceptionnelles, improbables ou erronées, mais pas pour les situations impossibles. Pour moi, la différence essentielle est la suivante :

  • Il devrait TOUJOURS être possible de produire un scénario de test qui exerce une instruction throw donnée. S'il n'est pas possible de produire un tel scénario 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 scénario de test qui provoque l'exécution d'une assertion. Si une assertion se déclenche, soit le code est erroné, soit l'assertion est erronée ; dans tous les cas, quelque chose doit être modifié dans le code.

C'est pourquoi je ne remplacerais pas une assertion par une exception. Si l'assertion ne peut pas être exécutée, alors Le 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.

22voto

Ned Batchelder Points 128913

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 de l'utilisateur.

Les affirmations testent les conditions qui "ne peuvent pas se produire". 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 de l'exécution), vous pouvez modifier leur comportement. Par exemple, il arrive souvent que les assertions ne soient même pas vérifiées lors de la construction d'une version, car elles introduisent une surcharge inutile. Il faut également se méfier de cette situation : vos tests peuvent ne pas être exécutés.

Si vous utilisez des exceptions au lieu des assertions, vous perdez une partie de la valeur :

  1. Le code est plus verbeux, puisque tester et lancer une exception représente au moins deux lignes, alors qu'une assert n'en représente qu'une.

  2. Votre code de test et de lancement sera toujours exécuté, tandis que les assertions peuvent être compilées.

  3. Vous perdez une partie de la 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 d'informations ici : http://nedbatchelder.com/text/assert.html

14voto

Tom Neyland Points 3772

EDIT : En réponse à la modification/note que vous avez faite dans votre message : Il semble que l'utilisation des exceptions soit la meilleure solution par rapport à l'utilisation 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 considérez que les exceptions et les assertions remplissent le même objectif, et vous essayez donc de déterminer laquelle serait la "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 avec des solutions différentes au même problème - ce n'est pas le cas. Les assertions et les exceptions ont chacune leur propre objectif, leurs forces et leurs faiblesses.

J'allais rédiger une réponse dans mes propres mots, mais ce texte rend mieux justice au concept que je ne l'aurais fait :

Station C# : Assertions

L'utilisation des déclarations d'assertion peut être une moyen efficace d'attraper la logique du programme programme au moment de l'exécution, et pourtant elles sont facilement filtrées du code de production de production. Une fois le développement terminé, le coût d'exécution de ces tests redondants redondants pour les erreurs de codage peut être être éliminé simplement en définissant le symbole du préprocesseur NDEBUG [qui désactive toutes les assertions] pendant la compilation. N'oubliez pas, cependant, de rappelez-vous que le code placé dans l'assertion assert lui-même sera omis dans la version de production.

Une assertion est utilisée au mieux pour tester un condition uniquement lorsque tous les suivantes :

* the condition should never be false if the code is correct,
* the condition is not so trivial so as to obviously be always true, and
* the condition is in some sense internal to a body of software.

Les assertions ne devraient presque jamais être utilisées pour détecter des situations qui surviennent pendant le fonctionnement normal d'un logiciel. Par exemple, les assertions doivent généralement pas être utilisées pour vérifier les erreurs dans l'entrée de l'utilisateur. Cependant, il peut être judicieux sens d'utiliser des assertions pour vérifier que qu'un appelant a déjà vérifié l'entrée l'utilisateur.

Fondamentalement, utilisez les exceptions pour les choses qui doivent être attrapées/traitées dans une application de production, utilisez les assertions pour effectuer des vérifications logiques qui seront utiles pour le développement mais désactivées en production.

10voto

drzaus Points 3344

Je pense qu'un exemple pratique (artificiel) peut aider à éclairer la différence :

(adapté de L'extension Batch de MoreLinq )

// 'public facing' method
public int DoSomething(List<string> stuff, object doohickey, int limit) {

    // validate user input and report problems externally with exceptions

    if(stuff == null) throw new ArgumentNullException("stuff");
    if(doohickey == null) throw new ArgumentNullException("doohickey");
    if(limit <= 0) throw new ArgumentOutOfRangeException("limit", limit, "Should be > 0");

    return DoSomethingImpl(stuff, doohickey, limit);
}

// 'developer only' method
private static int DoSomethingImpl(List<string> stuff, object doohickey, int limit) {

    // validate input that should only come from other programming methods
    // which we have control over (e.g. we already validated user input in
    // the calling method above), so anything using this method shouldn't
    // need to report problems externally, and compilation mode can remove
    // this "unnecessary" check from production

    Debug.Assert(stuff != null);
    Debug.Assert(doohickey != null);
    Debug.Assert(limit > 0);

    /* now do the actual work... */
}

Alors que Eric Lippert et al l'ont dit, vous n'affirmez que les choses que vous pensez être correctes, juste au cas où. vous (le développeur) l'a accidentellement mal utilisé ailleurs, pour que vous puissiez corriger votre code. En fait, vous lancez des exceptions lorsque vous ne contrôlez pas ou ne pouvez pas anticiper ce qui arrive, par exemple, pour la saisie de l'utilisateur afin que la personne qui lui a fourni les mauvaises données puisse réagir de manière appropriée (par exemple, l'utilisateur).

4voto

Andrew Cowenhoven Points 2371

Une autre pépite de Code complet :

"Une assertion est une fonction ou une macro qui se plaint bruyamment si une hypothèse n'est pas vraie. Utilisez les assertions pour documenter les hypothèses faites dans le code et pour débusquer des conditions inattendues. ...

"Pendant le développement, les assertions débusquent les hypothèses contradictoires, les conditions inattendues, les mauvaises valeurs transmises aux routines, et ainsi de suite."

Il ajoute ensuite quelques lignes directrices sur ce qui doit et ne doit pas être affirmé.

D'autre part, les exceptions :

"Utilisez le traitement des exceptions pour attirer l'attention sur les cas inattendus. Les cas exceptionnels doivent être traités de manière à les rendre évidents pendant le développement et récupérables lorsque le code de production est en cours d'exécution."

Si vous n'avez pas ce livre, vous devriez l'acheter.

Prograide.com

Prograide est une communauté de développeurs qui cherche à élargir la connaissance de la programmation au-delà de l'anglais.
Pour cela nous avons les plus grands doutes résolus en français et vous pouvez aussi poser vos propres questions ou résoudre celles des autres.

Powered by:

X