Question

Je suis un ingénieur en logiciel professionnel depuis environ un an, après avoir obtenu un diplôme en informatique. Je connaissais les assertions depuis un certain temps en C ++ et C, mais je n’avais aucune idée de leur existence jusqu’à récemment. C / .NET.

Notre code de production ne contient aucune affirmation et ma question est la suivante ...

Devrais-je commencer à utiliser Asserts dans notre code de production? Et si oui, quand son utilisation est-elle la plus appropriée? Serait-il plus logique de faire

Debug.Assert(val != null);

ou

if ( val == null )
    throw new exception();
Était-ce utile?

La solution

Dans le Débogage des applications Microsoft .NET 2.0 , John Robbins a une grande section sur assertions. Ses points principaux sont:

  1. Assert généreusement. Vous ne pouvez jamais avoir trop d’affirmations.
  2. Les assertions ne remplacent pas les exceptions. Les exceptions couvrent les exigences de votre code; les assertions couvrent les choses qu’il suppose.
  3. Une affirmation bien écrite peut vous dire non seulement ce qui s’est passé et où (comme une exception), mais pourquoi.
  4. Un message d'exception peut souvent être cryptique, vous obligeant à remonter dans le code pour recréer le contexte qui a provoqué l'erreur. Une assertion peut conserver l'état du programme au moment où l'erreur s'est produite.
  5. Les assertions servent également de documentation et expliquent aux autres développeurs les hypothèses implicites sur lesquelles repose votre code.
  6. La boîte de dialogue qui apparaît en cas d'échec d'une assertion vous permet d'attacher un débogueur au processus. Vous pouvez ainsi parcourir la pile comme si vous y aviez placé un point d'arrêt.

PS: Si vous avez aimé Code Complete, je vous recommande de le suivre avec ce livre. Je l'ai acheté pour apprendre à utiliser WinDBG et les fichiers de vidage, mais la première moitié contient de nombreux conseils pour éviter les bugs.

Autres conseils

Mettez Debug.Assert () partout dans le code où vous souhaitez que les contrôles de cohérence soient effectués pour garantir les invariants. Lorsque vous compilez une version Release (c’est-à-dire qu’aucune constante du compilateur DEBUG ), les appels à Debug.Assert () seront supprimés et gagnants. n'affecte pas les performances.

Vous devriez toujours lancer des exceptions avant d'appeler Debug.Assert () . L'assertion s'assure simplement que tout est comme prévu pendant votre développement.

De Code complet

  

8 Programmation défensive

     

8.2 Assertions

     

Une assertion est un code utilisé pendant le développement - généralement une routine   ou macro - qui permet à un programme de se vérifier lui-même pendant son exécution. Quand un   l'affirmation est vraie, cela signifie que tout fonctionne comme prévu.   Lorsqu'il est faux, cela signifie qu'il a détecté une erreur inattendue dans le   code. Par exemple, si le système suppose qu'une information client   fichier n’aura jamais plus de 50 000 enregistrements, le programme pourrait   contient une assertion que le nombre d'enregistrements est inférieur ou égal   à 50 000. Tant que le nombre d'enregistrements est inférieur ou égal à   50 000, l'affirmation sera silencieuse. S'il rencontre plus de   50 000 enregistrements, cependant, il «affirmera» fort qu'il existe un   erreur dans le programme.

     

Les assertions sont particulièrement utiles dans les grands programmes complexes.   dans les programmes de haute fiabilité. Ils permettent aux programmeurs de plus rapidement   éliminer les hypothèses d’interface incompatibles, les erreurs qui se glissent dans   le code est modifié, etc.

     

Une assertion prend généralement deux arguments: une expression booléenne qui   décrit l’hypothèse supposée vraie et un message à l'attention de   afficher si ce n'est pas le cas.

     

(…)

     

Normalement, vous ne voulez pas que les utilisateurs voient les messages d'assertion dans   code de production; les assertions sont principalement utilisées pendant le développement   et maintenance. Les assertions sont normalement compilées dans le code à   temps de développement et compilé hors du code pour la production. Pendant   développement, affirmations débusquant des hypothèses contradictoires,   conditions inattendues, mauvaises valeurs transmises aux routines, etc.   Au cours de la production, ils sont compilés à partir du code afin que le   les assertions ne dégradent pas les performances du système.

FWIW ... Je constate que mes méthodes publiques ont tendance à utiliser le if () {throw; } pour vous assurer que la méthode est appelée correctement. Mes méthodes privées ont tendance à utiliser Debug.Assert () .

L’idée est que, avec mes méthodes privées, c’est moi qui suis sous contrôle, donc si je commence à appeler une de mes propres méthodes privées avec des paramètres incorrects, j’ai brisé ma propre hypothèse quelque part - je devrais n'ont jamais eu dans cet état. En production, ces affirmations privées devraient idéalement être un travail inutile, car je suis censé maintenir mon état interne valide et cohérent. Contraste avec les paramètres donnés aux méthodes publiques, pouvant être appelées par n'importe qui au moment de l’exécution: j’ai encore besoin de faire respecter les contraintes de paramètres en lançant des exceptions.

De plus, mes méthodes privées peuvent toujours générer des exceptions si quelque chose ne fonctionne pas au moment de l'exécution (erreur réseau, erreur d'accès aux données, données incorrectes extraites d'un service tiers, etc.). Mes affirmations sont juste là pour m'assurer que je n'ai pas brisé mes propres hypothèses internes concernant l'état de l'objet.

Utilisez des assertions pour vérifier les hypothèses du développeur et les exceptions pour vérifier les hypothèses de l'environnement.

Si j'étais vous, je ferais:

Debug.Assert(val != null);
if ( val == null )
    throw new exception();

Ou pour éviter des vérifications de condition répétées

if ( val == null )
{
    Debug.Assert(false,"breakpoint if val== null");
    throw new exception();
}

Si vous souhaitez des assertions dans votre code de production (c'est-à-dire des versions Release), vous pouvez utiliser Trace.Assert au lieu de Debug.Assert.

Bien entendu, cela ajoute une surcharge à votre exécutable de production.

De même, si votre application s'exécute en mode interface utilisateur, la boîte de dialogue Assertion s'affiche par défaut, ce qui peut paraître un peu déconcertant pour vos utilisateurs.

Vous pouvez remplacer ce comportement en supprimant DefaultTraceListener: consultez la documentation de Trace.Listeners dans MSDN.

En résumé,

  • Utilisez Debug.Assert librement pour vous aider à détecter les bogues dans les versions Debug.

  • Si vous utilisez Trace.Assert en mode interface utilisateur, vous souhaiterez probablement supprimer le DefaultTraceListener afin d'éviter de déconcerter les utilisateurs.

  • Si la condition que vous testez est une chose que votre application ne peut pas gérer, il est probablement préférable de lever une exception pour éviter toute interruption de l'exécution. Sachez qu'un utilisateur peut choisir d'ignorer une assertion.

Les assertions sont utilisées pour intercepter l'erreur du programmeur (et non l'utilisateur). Ils ne doivent être utilisés que lorsqu'il n'y a aucune chance qu'un utilisateur puisse provoquer le déclenchement de l'assertion. Si vous écrivez une API, par exemple, les assertions ne doivent pas être utilisées pour vérifier qu'un argument n'est pas nul dans les méthodes qu'un utilisateur de l'API pourrait appeler. Mais il pourrait être utilisé dans une méthode privée non exposée dans votre API pour affirmer que VOTRE code ne transmet jamais un argument nul lorsqu'il n'est pas supposé le faire.

Je préfère généralement les exceptions aux assertions quand je ne suis pas sûr.

Surtout jamais dans mon livre. Dans la grande majorité des cas, si vous voulez vérifier si tout est sain d'esprit, jetez-le s'il ne l'est pas.

Ce que je n’aime pas, c’est le fait que la construction d’un débogage est fonctionnellement différente de celle d’une version finale. Si une assertion de débogage échoue mais que la fonctionnalité fonctionne dans la version, comment cela a-t-il un sens? C'est encore mieux quand l'asserter a longtemps quitté l'entreprise et que personne ne sait cette partie du code. Ensuite, vous devez passer une partie de votre temps à explorer la question pour voir si c'est vraiment un problème ou pas. Si c'est un problème, alors pourquoi la personne qui lance n'est-elle pas?

Pour moi, cela suggère d'utiliser Debug.Asserts pour reporter le problème à quelqu'un d'autre, résolvez-le vous-même. Si quelque chose est censé être le cas et que ce n'est pas alors jeté.

Je suppose qu'il existe peut-être des scénarios critiques en termes de performances pour lesquels vous souhaitez optimiser vos assertions et qui sont utiles là-bas, mais je ne suis pas encore confronté à un tel scénario.

En bref

Les assertions sont utilisées pour les gardes et pour la vérification des contraintes de conception par contrat, à savoir:

  • Assert devrait être réservé aux versions Debug et non-Production. Les assertions sont généralement ignorées par le compilateur dans les versions Release.
  • Assert peut rechercher les bogues / conditions inattendues qui SONT sous le contrôle de votre système
  • Assert NE constitue PAS un mécanisme de validation de première ligne des entrées utilisateur ou des règles métier
  • Assure si pas ne doit être utilisé pour détecter des conditions environnementales inattendues (hors du contrôle du code), par exemple. mémoire insuffisante, défaillance réseau, défaillance de la base de données, etc. Bien que cela soit rare, ces conditions doivent être attendues (et le code de votre application ne peut pas résoudre des problèmes tels qu'une défaillance matérielle ou l'épuisement des ressources). En règle générale, des exceptions sont levées. Votre application peut alors prendre des mesures correctives (réessayer une opération de base de données ou de réseau, tenter de libérer de la mémoire en cache) ou abandonner normalement si l’exception ne peut pas être gérée.
  • Une assertion ayant échoué devrait être fatale à votre système - c'est-à-dire qu'à la différence d'une exception, n'essayez pas d'attraper ou de gérer l'échec Asserts - votre code fonctionne dans un territoire inattendu. Les traces de pile et les vidages sur incident peuvent être utilisés pour déterminer ce qui ne va pas.

Les affirmations ont un énorme avantage:

  • Pour vous aider à trouver la validation manquante des entrées utilisateur ou des bogues amont dans le code de niveau supérieur.
  • Les assertions dans la base de code transmettent clairement au lecteur les hypothèses formulées dans le code
  • L'assertion sera vérifiée à l'exécution dans les versions Debug .
  • Une fois que le code a été testé de manière exhaustive, sa reconstruction en tant que version supprime la surcharge de performances liée à la vérification de l'hypothèse (mais offre l'avantage qu'une construction ultérieure de débogage annulera toujours les contrôles, si nécessaire).

... Plus de détails

Debug.Assert exprime une condition supposée relative à l'état par le reste du bloc de code sous le contrôle du programme. Cela peut inclure l'état des paramètres fournis, l'état des membres d'une instance de classe ou le fait que le retour d'un appel de méthode se trouve dans sa plage contractée / conçue. En règle générale, les assertions doivent bloquer le thread / processus / programme avec toutes les informations nécessaires (traçage de pile, vidage sur incident, etc.), car elles indiquent la présence d’un bogue ou d’une condition non prise en compte qui n’a pas été conçue pour gérer les échecs d’assertions), à une exception près: quand une assertion elle-même pourrait causer plus de dégâts que le bogue (par exemple, les contrôleurs de la circulation aérienne ne voudraient pas d’un YSOD lorsqu’un aéronef passe sous-marin, bien qu’il soit sans objet de déployer une version de débogage production ...)

Quand devriez-vous utiliser Asserts?  - À tout moment dans un système, ou dans une API de bibliothèque, ou un service où les entrées d'une fonction ou d'un état d'une classe sont supposées valides (par exemple, lorsque la validation a déjà été effectuée sur une entrée utilisateur dans la couche de présentation d'un système, l'entreprise et Les classes de données supposent généralement que les vérifications nulles, les vérifications de plage, les vérifications de longueur de chaîne, etc.  - Les vérifications Assert courantes incluent les hypothèses dans lesquelles une hypothèse non valide aboutirait à une déréférencement d'objet nulle, à un diviseur égal à zéro, à un dépassement de capacité arithmétique numérique ou à la date, et à un comportement général hors bande / non conçu pour le comportement (par exemple, un comportement 32 bits). int étant utilisé pour modéliser l’âge d’un être humain, il serait prudent de d’affirmer que cet âge se situe en réalité entre 0 et 125 environ (les valeurs de -100 à 10 ^ 10 n’ont pas été conçues).

Contrats de code .Net
Dans la pile .Net, vous pouvez utiliser les contrats de code en plus ou au lieu de en utilisant Debug.Assert . Les contrats de code peuvent formaliser davantage la vérification d'état et aider à détecter les violations d'hypothèses au moment de la compilation (ou peu de temps après si elles sont exécutées comme vérification en arrière-plan dans un environnement de développement intégré).

Les contrôles DBC (Design by Contract) disponibles incluent:

  • Contract.Requires - Conditions préalables contractées
  • Contract.Ensures - PostConditions sous contrat
  • Invariant - Exprime une hypothèse sur l'état d'un objet à tous les points de sa vie.
  • Contract.Assumes - pacifie le vérificateur statique lorsqu'un appel à des méthodes décorées non contractuelles est effectué.

Selon la norme IDesign , vous devez

  

Affirmez chaque hypothèse. En moyenne, chaque cinquième ligne est une affirmation.

using System.Diagnostics;

object GetObject()
{...}

object someObject = GetObject();
Debug.Assert(someObject != null);

En tant que clause de non-responsabilité, je dois mentionner que je n’ai pas trouvé pratique d’appliquer cette IRL. Mais c’est leur norme.

Utilisez des assertions uniquement dans les cas où vous souhaitez que la vérification soit supprimée pour les versions validées. N'oubliez pas que vos assertions ne se déclencheront pas si vous ne compilez pas en mode débogage.

Étant donné votre exemple de vérification à null, s'il s'agit d'une API interne uniquement, je pourrais utiliser une assertion. Si c'est dans une API publique, j'utiliserais certainement la vérification explicite.

Toutes les assertions doivent constituer du code pouvant être optimisé pour:

Debug.Assert(true);

Parce qu’il vérifie quelque chose que vous avez déjà supposé vrai. Exemple:

public static void ConsumeEnumeration<T>(this IEnumerable<T> source)
{
  if(source != null)
    using(var en = source.GetEnumerator())
      RunThroughEnumerator(en);
}
public static T GetFirstAndConsume<T>(this IEnumerable<T> source)
{
  if(source == null)
    throw new ArgumentNullException("source");
  using(var en = source.GetEnumerator())
  {
    if(!en.MoveNext())
      throw new InvalidOperationException("Empty sequence");
    T ret = en.Current;
    RunThroughEnumerator(en);
    return ret;
  }
}
private static void RunThroughEnumerator<T>(IEnumerator<T> en)
{
  Debug.Assert(en != null);
  while(en.MoveNext());
}

Dans ce qui précède, il existe trois approches différentes des paramètres nuls. Le premier l'accepte comme étant admissible (il ne fait simplement rien). La seconde lève une exception pour le code appelant à gérer (ou non, entraînant un message d'erreur). La troisième suppose que cela ne peut pas se produire et affirme qu'il en est ainsi.

Dans le premier cas, il n'y a pas de problème.

Dans le second cas, il y a un problème avec le code appelant - il n'aurait pas dû appeler GetFirstAndConsume avec null, il renvoie donc une exception.

Dans le troisième cas, il y a un problème avec ce code, car il aurait déjà dû être vérifié que en! = null avant qu'il ne soit appelé, afin qu'il ne soit pas vrai, c'est un bug . Autrement dit, le code devrait théoriquement être optimisé pour Debug.Assert (true) , sicne en! = Null devrait toujours être true !

Je pensais ajouter quatre cas supplémentaires dans lesquels Debug.Assert peut être le bon choix.

1) Une chose que je n'ai pas vue mentionnée ici est la couverture conceptuelle supplémentaire que les assertions peuvent fournir lors de tests automatisés . À titre d'exemple simple:

Lorsqu'un auteur de numéro supérieur modifie un appelant de niveau supérieur en pensant qu'il a étendu la portée du code pour gérer des scénarios supplémentaires, idéalement (!) il rédigera des tests unitaires pour couvrir cette nouvelle condition. Il se peut alors que le code entièrement intégré semble bien fonctionner.

Cependant, une faille subtile a été introduite, mais n’a pas été détectée dans les résultats des tests. Dans ce cas, l'appelé est devenu non déterministe et seul se produit pour fournir le résultat attendu. Ou peut-être a-t-il généré une erreur d'arrondi inaperçu. Ou causé une erreur qui a été compensée également ailleurs. Ou accordé non seulement l'accès demandé, mais des privilèges supplémentaires qui ne devraient pas être accordés. Etc.

À ce stade, les instructions Debug.Assert () contenues dans l'appelé associées au nouveau cas (ou au cas d'extrémité) piloté par des tests unitaires peuvent fournir une notification inestimable lors du test que les hypothèses de l'auteur initial ont été invalidées et que le code ne doit pas être publié sans révision supplémentaire. Les affirmations avec des tests unitaires sont les partenaires parfaits.

2) De plus, certains tests sont simples à écrire, mais coûteux et inutiles compte tenu des hypothèses de départ . Par exemple:

Si un objet est accessible uniquement à partir d'un certain point d'entrée sécurisé, une requête supplémentaire doit-elle être effectuée sur une base de données de droits réseau à partir de chaque méthode d'objet afin de garantir que l'appelant dispose des autorisations nécessaires? Sûrement pas. Peut-être que la solution idéale inclut la mise en cache ou une autre extension des fonctionnalités, mais la conception n'en nécessite pas. Debug.Assert () s'affichera immédiatement lorsque l'objet aura été attaché à un point d'entrée non sécurisé.

3) Dans certains cas, votre produit peut ne générer aucune interaction de diagnostic utile pour tout ou partie de ses opérations lorsqu'il est déployé en mode de validation . Par exemple:

Supposons qu’il s’agisse d’un périphérique embarqué temps réel. Lancer des exceptions et redémarrer lorsqu'il rencontre un paquet mal formé est contre-productif. Au lieu de cela, le périphérique peut tirer parti du meilleur fonctionnement possible, même au point de générer du bruit en sortie. De plus, il peut ne pas avoir d'interface humaine, de périphérique de journalisation, ni même être physiquement accessible par l'homme lorsqu'il est déployé en mode de publication. La meilleure façon de détecter les erreurs est d'obtenir le même résultat. Dans ce cas, les assertions libérales et les tests préalables approfondis sont plus utiles que les exceptions.

4) Enfin, certains tests ne sont pas nécessaires uniquement parce que l'appelé est perçu comme extrêmement fiable . Dans la plupart des cas, plus le code est réutilisable, plus on s’efforce de le rendre fiable. Par conséquent, il est commun à Exception pour les paramètres inattendus des appelants, mais Assert pour les résultats inattendus de callees. Par exemple:

Si une opération String.Find principale indique qu'elle renvoie un -1 lorsque le critère de recherche n'est pas trouvé, vous pourrez peut-être effectuer une opération en toute sécurité plutôt que Trois. Toutefois, s’il renvoie -2 , vous n’auriez peut-être aucun recours raisonnable. Il serait inutile de remplacer le calcul le plus simple par un autre qui teste séparément une valeur -1 , et déraisonnable dans la plupart des environnements de publication pour que votre code contienne des tests garantissant que les bibliothèques principales fonctionnent correctement. Dans ce cas, les affirmations sont idéales.

Citation extraite de Le programmeur pragmatique: de compagnon à maître

  

Laisser les assertions activées

     

Il existe un malentendu courant concernant les affirmations, promulguées par   les personnes qui écrivent des compilateurs et des environnements linguistiques. Ça va   quelque chose comme ceci:

     

Les assertions ajoutent une surcharge au code. Parce qu'ils vérifient   cela ne devrait jamais arriver, ils ne seront déclenchés que par un bug dans le   code. Une fois que le code a été testé et expédié, ils ne sont plus   nécessaire et doit être désactivé pour que le code soit exécuté plus rapidement.   Les assertions sont une facilité de débogage.

     

Il y a deux suppositions manifestement erronées ici. Tout d'abord, ils supposent que   le test trouve tous les bugs. En réalité, pour tout programme complexe, vous   sont peu susceptibles de tester même un pourcentage infime des permutations   votre code sera transmis (voir Test impitoyable).

     

Deuxièmement, les optimistes oublient que votre programme fonctionne dans un   monde dangereux. Pendant les tests, les rats ne rongeront probablement pas   câble de communication, une personne jouant à un jeu n'épuise pas la mémoire, et   les fichiers journaux ne rempliront pas le disque dur. Ces choses pourraient arriver quand   votre programme s'exécute dans un environnement de production. Votre première ligne de   la défense vérifie toute erreur possible, et votre seconde utilise   des affirmations pour essayer de détecter celles que vous avez manquées.

     

Désactiver les assertions lorsque vous livrez un programme en production est   comme traverser un fil haut sans filet parce que vous l'avez fait une fois   dans la pratique . Il y a une valeur dramatique, mais il est difficile de trouver la vie   assurance.

     

Même si vous rencontrez des problèmes de performances, désactivez uniquement ceux-ci.   assertions qui vous ont vraiment frappé .

Vous devriez toujours utiliser la deuxième approche (lever des exceptions).

De même, si vous êtes en production (et que vous avez une version release-build), il vaut mieux lancer une exception (et laisser l’application planter dans le pire des cas) que de travailler avec des valeurs non valides et éventuellement de détruire les données de votre client (qui peut coûter des milliers de dollars).

Vous devez utiliser Debug.Assert pour rechercher les erreurs logiques dans vos programmes. Le compliant ne peut vous informer que des erreurs de syntaxe. Vous devriez donc utiliser les instructions Assert pour tester les erreurs logiques. Par exemple, tester un programme qui vend des voitures pour lesquelles seules les BMW bleues devrait bénéficier d’une réduction de 15%. Le compliant pourrait ne rien vous dire si votre programme est logiquement correct, mais une déclaration d’assertion pourrait.

J'ai lu les réponses ici et je pensais que je devrais ajouter une distinction importante. Les assertions sont utilisées de deux manières très différentes. L'un d'eux est un raccourci temporaire pour le développeur "Cela ne devrait pas vraiment arriver, mais si cela me permet de savoir ce que je peux faire", c'est un peu comme un point d'arrêt conditionnel, dans les cas où votre programme peut continuer. L’autre est un moyen de formuler des hypothèses sur les états de programme valides dans votre code.

Dans le premier cas, les assertions n'ont même pas besoin d'être dans le code final. Vous devez utiliser Debug.Assert pendant le développement et vous pouvez les supprimer si / quand vous n'en avez plus besoin. Si vous souhaitez les quitter ou si vous oubliez de les supprimer, pas de problème, car ils n'auront aucune conséquence dans les compilations Release.

Mais dans le second cas, les assertions font partie du code. Ils affirment que vos hypothèses sont vraies et les documentent également. Dans ce cas, vous voulez vraiment les laisser dans le code. Si le programme est dans un état non valide, il ne devrait pas être autorisé à continuer. Si vous ne pouviez pas vous permettre d’atteindre ce résultat, vous n’utiliseriez pas C #. D'une part, il pourrait être utile de pouvoir joindre un débogueur si cela se produit. D'autre part, vous ne voulez pas que la trace de pile apparaisse sur vos utilisateurs et peut-être plus important encore, vous ne voulez pas qu'ils puissent l'ignorer. De plus, s'il s'agit d'un service, il sera toujours ignoré. Par conséquent, en production, le bon comportement consisterait à lancer une exception et à utiliser la gestion normale des exceptions de votre programme, qui pourrait afficher un message intéressant à l'utilisateur et consigner les détails.

Trace.Assert est le moyen idéal pour y parvenir. Il ne sera pas supprimé en production et peut être configuré avec différents écouteurs à l'aide de app.config. Donc, pour le développement, le gestionnaire par défaut convient, et pour la production, vous pouvez créer un simple TraceListener, comme ci-dessous, qui lève une exception et l’active dans le fichier de configuration de la production.

using System.Diagnostics;

public class ExceptionTraceListener : DefaultTraceListener
{
    [DebuggerStepThrough]
    public override void Fail(string message, string detailMessage)
    {
        throw new AssertException(message);
    }
}

public class AssertException : Exception
{
    public AssertException(string message) : base(message) { }
}

Et dans le fichier de configuration de production:

<system.diagnostics>
  <trace>
    <listeners>
      <remove name="Default"/>
      <add name="ExceptionListener" type="Namespace.ExceptionTraceListener,AssemblyName"/>
    </listeners>
  </trace>
 </system.diagnostics>

Je ne sais pas comment cela se passe en C # et .NET, mais en C, assert () ne fonctionnera que s'il est compilé avec -DDEBUG - l'utilisateur final ne verra jamais assert () s'il n'est pas compilé. C'est pour développeur seulement. Je l'utilise très souvent, il est parfois plus facile de suivre les bugs.

Je ne les utiliserais pas dans le code de production. Lance des exceptions, intercepte et enregistre.

Il faut également être prudent dans asp.net, car une assertion peut apparaître sur la console et geler la ou les demandes.

Licencié sous: CC-BY-SA avec attribution
Non affilié à StackOverflow
scroll top