web-dev-qa-db-fra.com

Debug.Assert vs Exception Throwing

J'ai lu beaucoup de articles (et quelques autres similaires questions qui ont été postées sur StackOverflow) sur comment et quand utiliser des assertions et je les ai bien comprises. Mais je ne comprends toujours pas quel type 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 ayant échoué consiste à «arrêter le monde» et à 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 que je lève l'exception, et en 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 où elle ne devrait pas être pourrait simplement causer toutes sortes de "comportements indésirables", aussi, de mon point de vue, 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 quelque chose me manque?

Note: Je comprends parfaitement la différence "en théorie" (Debug vs Release, modèles d'utilisation, etc.), mais à mon avis, je ferais mieux de lancer une exception au lieu de faire une assertion. Étant donné que si un bogue est découvert sur une version de production, je voudrais tout de même que "l'assertion" échoue (après tout, le "temps système" est ridiculement faible), je ferais donc mieux de lancer une exception à la place.


Edit: À mon avis, si une assertion échouait, cela signifiait que l'application entrait dans un é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. La même chose vaut pour les deux

84
unknown

Bien que je convienne que votre raisonnement est plausible - c’est-à-dire que, si une assertion est violée de manière inattendue, il est logique d’arrêter l’exécution en lançant -, personnellement, je n’utiliserais pas les exceptions à la place des assertions. Voici pourquoi:

Comme d'autres l'ont dit, les assertions devraient documenter des situations qui sont impossibles, de manière à informer le développeur si la situation prétendument impossible se concrétisait. Les exceptions, en revanche, fournissent un mécanisme de flux de contrôle pour les situations exceptionnelles, improbables ou erronées, mais non impossibles. Pour moi, la principale différence est la suivante:

  • Il devrait TOUJOURS être possible de produire un scénario de test qui exécute une instruction de projection donnée. S'il n'est pas possible de produire un tel cas de test, votre programme contient un chemin de code 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 entraînant le déclenchement d'une assertion. Si une assertion est déclenchée, le code est incorrect ou 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 être déclenchée, alors le remplacer par une exception signifie que vous avez un chemin de code non vérifiable dans votre programme} Je n'aime pas les chemins de code non testables. 

162
Eric Lippert

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 mal agi. Par exemple, n'utilisez jamais d'assertion pour vérifier les entrées de l'utilisateur.

Assert test pour des 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 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: vos tests peuvent même ne pas être exécutés.

Si vous utilisez des exceptions au lieu d’assertions, vous perdez une certaine valeur:

  1. Le code est plus détaillé, car tester et lancer une exception nécessite au moins deux lignes, tandis qu'une assertion n'en contient 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 certaines communications avec les autres développeurs, car les assertions ont une signification différente de celle du code de produit qui vérifie et jette. Si vous testez réellement une assertion de programmation, utilisez une assertion.

Plus ici: http://nedbatchelder.com/text/assert.html

15
Ned Batchelder

EDIT:En réponse à la modification/note que vous avez faite dans votre message: Il semble que l'utilisation d'exceptions est la bonne chose à utiliser plutôt que d'utiliser des assertions pour le type de choses que vous essayez à accomplir ... Je pense que le principal obstacle que vous rencontrez est que vous envisagez des exceptions et des assertions pour atteindre le même objectif, et que vous essayez donc de déterminer lequel serait le mieux à utiliser. Si les assertions et les exceptions peuvent être utilisées, ne confondez pas le fait qu’elles représentent différentes solutions au même problème - elles ne le sont pas. Les assertions et les exceptions ont chacune leur but, leurs forces et leurs faiblesses.} _

J'allais taper une réponse avec mes propres mots mais cela rend le concept plus juste que ce que j'aurais eu:

C # Station: Assertions

L'utilisation d'assert assert peut être un moyen efficace de saisir la logique du programme erreurs au moment de l'exécution, et pourtant elles sont facilement filtré de la production code. Une fois le développement terminé, le coût d'exécution de ces redondants les tests d’erreurs de codage peuvent être éliminé simplement en définissant le symbole de préprocesseur NDEBUG [which désactive toutes les assertions] pendant compilation. Assurez-vous, cependant, pour rappelez-vous ce code placé dans le s’affirmer sera omis dans le version de production. 

Il est préférable d’utiliser une assertion pour tester un condition que lorsque tous les attente suivante:

* 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 pouvant survenir pendant le fonctionnement normal du logiciel. Par exemple, les assertions devraient normalement ne pas être utilisé pour vérifier les erreurs dans un entrée de l'utilisateur. Il peut cependant faire sens d'utiliser des assertions pour vérifier que un appelant a déjà vérifié le nom d'un utilisateur contribution.

Fondamentalement, utilisez des exceptions pour les éléments qui doivent être interceptés/traités dans une application de production, utilisez des assertions pour effectuer des contrôles logiques qui seront utiles pour le développement mais désactivés en production. 

11
Tom Neyland

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

(adapté de extension du lot 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... */
}

Donc, comme l'ont dit Eric Lippert et al., Vous n'affirmez que des éléments que vous vous attendez à être corrects, juste au cas où vous (le développeur) l'a mal utilisé ailleurs, alors vous pouvez réparer votre code. Vous lâchez des exceptions lorsque vous n'avez aucun contrôle sur ou ne pouvez pas anticiper ce qui vous arrive, par exemple, pour une entrée utilisateur, de sorte que tout ce qui a donné des données incorrectes puisse répondre correctement (par exemple, l'utilisateur).

6
drzaus

Une autre pépite de Code Complete :

"Une assertion est une fonction ou une macro Qui se plaint fort si une hypothèse Est fausse. Utilisez des assertions pour documenter Des hypothèses formulées dans le code et vider Des conditions inattendues. ...

"Pendant le développement, les assertions chassent Des hypothèses contradictoires, Des conditions inattendues, de mauvaises valeurs Transmises à des routines, etc."

Il ajoute quelques lignes directrices sur ce qui devrait ou ne devrait pas être affirmé.

Par contre, des exceptions:

"Utilisez la gestion 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.

4
Andrew Cowenhoven

Supposons que vous fassiez partie d'une assez grande équipe et que plusieurs personnes travaillent sur la même base de code général, y compris le chevauchement de classes .. Vous pouvez créer une méthode appelée par plusieurs autres méthodes et éviter les conflits de verrous. vous n'y ajoutez pas de verrou distinct, mais plutôt "supposez" qu'il avait été verrouillé auparavant par la méthode d'appel avec un verrou spécifique ..., tel que, Debug.Assert (RepositoryLock.IsReadLockHeld || RepositoryLock.IsWriteLockHeld) ; Les autres développeurs peuvent oublier un commentaire qui dit que la méthode d'appel doit utiliser le verrou, mais ils ne peuvent pas l'ignorer.

0
daniel

Utilisez des assertions pour des choses qui SONT possibles mais ne devraient pas arriver (si c'était impossible, pourquoi mettriez-vous une assertion?).

Est-ce que cela ne ressemble pas à un cas d'utiliser une Exception? Pourquoi voudriez-vous utiliser une assertion au lieu d'une Exception

Parce qu'il devrait y avoir un code appelé avant votre assertion qui empêcherait le paramètre de l'assertion d'être faux.

Généralement, il n'y a pas de code avant votre Exception qui garantit qu'il ne sera pas jeté.

Pourquoi est-il bon que Debug.Assert() soit compilé dans prod? Si vous voulez en savoir plus dans le débogage, ne voudriez-vous pas en savoir plus dans prod?

Vous ne le voulez que pendant le développement, car une fois que vous avez trouvé les situations Debug.Assert(false), vous écrivez du code afin de garantir que Debug.Assert(false) ne se reproduira plus . Debug.Assert(false) et corrigées, la Debug.Assert() peut être compilée en toute sécurité car elles sont maintenant redondantes.

0
Backwards_Dave

Debug.Assert par défaut ne fonctionnera que dans les versions de débogage. Par conséquent, si vous souhaitez détecter un comportement inattendu, vous devez utiliser des exceptions ou activer la constante de débogage dans les propriétés du projet général ne pas être une bonne idée).

0
Mez