Comment documenter les exceptions levées dans c # /. Net

140

J'écris actuellement un petit framework qui sera utilisé en interne par d'autres développeurs au sein de l'entreprise.

Je souhaite fournir de bonnes informations Intellisense, mais je ne sais pas comment documenter les exceptions levées.

Dans l'exemple suivant:

public void MyMethod1()
{
    MyMethod2();

    // also may throw InvalidOperationException
}

public void MyMethod2()
{
    System.IO.File.Open(somepath...); // this may throw FileNotFoundException

    // also may throw DivideByZeroException
}

Je sais que le balisage pour documenter les exceptions est:

/// <exception cref="SomeException">when things go wrong.</exception>

Ce que je ne comprends pas, c'est comment documenter les exceptions levées par le code appelé par MyMethod1() ?

  • Dois-je documenter les exceptions levées par MyMethod2()
  • Dois-je documenter les exceptions levées par File.Open()?

Quelle serait la meilleure façon de documenter les exceptions possibles?

Arnold Zokas
la source
4
Je sais que ce n'est pas exactement ce que vous demandiez (et c'est une question très ancienne) mais Eric Lippert (développeur principal du compilateur Microsoft C # et des équipes de conception) a écrit un article de blog sur les 4 types d'exceptions que je pense que chaque développeur devrait être pensé lors de l'écriture du code de gestion des exceptions: blogs.msdn.com/b/ericlippert/archive/2008/09/10/…
javajavajavajavajava
@javajavajavajavajava Merci pour le lien - il vaut vraiment la peine d'être lu.
Arnold Zokas
1
Je pense que c'est une question valable car il n'est pas du tout évident de savoir comment documenter correctement les exceptions en C # et les vues 50K montrent que ce n'est pas non plus évident pour beaucoup de gens. La deuxième réponse la plus votée est très utile car elle montre l'utilisation de xmldocs existants pour documenter cela. Voter pour rouvrir. Cette raison proche "basée sur l'opinion" tue beaucoup de questions de programmation réellement très utiles.
Alexei le

Réponses:

110

Vous devez documenter chaque exception qui pourrait être levée par votre code, y compris celles de toutes les méthodes que vous pourriez appeler.

Si la liste devient un peu grande, vous pouvez créer votre propre type d'exception. Attrapez tous ceux que vous pourriez rencontrer dans votre méthode, enveloppez-les dans votre exception et lancez-les.

Un autre endroit où vous voudrez peut-être le faire de cette façon est si votre méthode est sur le visage de votre API. Tout comme une façade simplifie plusieurs interfaces en une seule interface, votre API doit simplifier plusieurs exceptions en une seule exception. Facilite l'utilisation de votre code pour les appelants.


Pour répondre à certaines des préoccupations d'Andrew (à partir des commentaires), il existe trois types d'exceptions: celles que vous ne connaissez pas, celles que vous connaissez et dont vous ne pouvez rien faire, et celles que vous connaissez et pour lesquelles vous pouvez faire quelque chose.

Ceux que vous ne connaissez pas veulent lâcher prise. C'est le principe de l'échec rapide - mieux votre application se bloque que d'entrer dans un état où vous pourriez finir par corrompre vos données. Le crash vous dira ce qui s'est passé et pourquoi, ce qui peut aider à déplacer cette exception de la liste "celles que vous ne connaissez pas".

Ceux que vous connaissez et pour lesquels vous ne pouvez rien faire sont des exceptions comme OutOfMemoryExceptions. Dans des cas extrêmes, vous voudrez peut-être gérer des exceptions comme celle-ci, mais à moins que vous n'ayez des exigences assez remarquables, vous les traitez comme la première catégorie - laissez-les partir. Avez - vous avez à documenter ces exceptions? Vous auriez l'air assez stupide de documenter les MOO sur chaque méthode qui crée un objet.

Ceux que vous connaissez et pour lesquels vous pouvez faire quelque chose sont ceux que vous devriez documenter et emballer.

Vous pouvez trouver plus de directives sur la gestion des exceptions ici.


la source
3
Je dois admettre que cela ne semble pas très pratique. Je ne peux pas imaginer combien d'exceptions potentielles peuvent être levées par n'importe quel code que je pourrais appeler, en plus il y a des choses comme OutOfMemoryException que vous ne voudriez pas attraper et encapsuler.
Andrew Hare
3
Votre réponse est-elle bonne, mais ce sont en fait deux réponses qui se contredisent. «documentez toutes les exceptions qui pourraient être lancées par votre code» et «celles que vous connaissez et sur lesquelles vous pouvez faire quelque chose sont celles que vous devriez documenter».
tymtam
2
@Tymek: Non. La première moitié a répondu à la question «comment dois-je documenter les exceptions», la deuxième partie a souligné la réponse manifestement évidente à «quelles exceptions dois-je documenter». Le premier n'implique pas que vous documentiez toutes les exceptions qui peuvent éventuellement se produire. Certaines personnes sont trop littérales, ce qui a nécessité la seconde moitié.
5
@Tymek Je pense que votre argument pourrait être que si vous pouvez faire quelque chose à ce sujet, pourquoi ne pas faire quelque chose à ce sujet au lieu de le relancer et de le documenter? Il peut être plus véridique de dire "Ceux que vous connaissez et dont le code client peut faire quelque chose". Cela supprime la contradiction, car ce sont les exceptions idéales à documenter.
mo.
En ce qui concerne les exceptions que vous «laissez aller», vous pouvez toujours les attraper à un niveau inférieur qui les enregistre ou quelque chose du genre. Tu sais; juste faire un moyen convivial de laisser le programme planter.
Nyerguds
96

Vous devez utiliser la documentation xml standard .

/// <exception cref="InvalidOperationException">Why it's thrown.</exception>
/// <exception cref="FileNotFoundException">Why it's thrown.</exception>
/// <exception cref="DivideByZeroException">Why it's thrown.</exception>
public void MyMethod1()
{
    MyMethod2();
    // ... other stuff here
}

/// <exception cref="FileNotFoundException">Why it's thrown.</exception>
/// <exception cref="DivideByZeroException">Why it's thrown.</exception>
public void MyMethod2()
{
    System.IO.File.Open(somepath...);
}

/// <exception cref="FileNotFoundException">Why it's thrown.</exception>
public void MyMethod3()
{
    try
    {
        MyMethod2();
    }
    catch (DivideByZeroException ex)
    {
        Trace.Warning("We tried to divide by zero, but we can continue.");
    }
}

L'intérêt de procéder de cette manière est que vous fournissez une documentation sur les exceptions connues qui peuvent se produire. Cette documentation est disponible dans l'intellisense si vous utilisez Visual Studio et peut vous rappeler (ou à d'autres) plus tard les exceptions auxquelles vous pouvez vous attendre.

Vous souhaitez spécifier les types d'exceptions spécifiques, car vous pourrez peut-être gérer un type d'exception, tandis que d'autres types sont le résultat d'un problème grave et ne peuvent pas être corrigés.

frissons42
la source
1
En quoi cela ajoute-t-il de la valeur? Par exemple, toutes ces exceptions sont des dérivations de type Exception. D'après mon expérience, il ne sera pas pratique de penser à tous les autres types d'exceptions qui pourraient être générés par les autres API appelées dans vos méthodes. Mon point est que nous ne devrions pas nous inquiéter des exceptions qui sont lancées à partir d'une méthode que celles qui contiennent des informations commerciales.
Illuminati
7
@ShiranGinige votre expérience est fausse.
Grozz
35

Vous pouvez faciliter votre processus de documentation en utilisant plusieurs excellents compléments. L'un d'eux est GhostDoc , un complément gratuit pour Visual Studio qui génère des commentaires XML-doc. De plus, si vous utilisez ReSharper , jetez un œil à l'excellent Plugin Agent Johnson pour ReSharper, qui ajoute une option pour générer des commentaires XML pour les exceptions levées.

Mise à jour: Il semble qu'Agen Johnson ne soit pas disponible pour R # 8, checkout Exceptionnel pour ReSharper comme alternative ...

Étape 1: GhostDoc génère le commentaire XML (Ctrl-Shift-D), tandis que le plugin Agent Johnson pour ReSharper suggère également de documenter l'exception:

étape 1

Étape 2: Utilisez la touche de raccourci de ReSharper (Alt-Entrée) pour ajouter également la documentation d'exception:

étape 2 http://i41.tinypic.com/osdhm

J'espère que cela pourra aider :)

Igal Tabachnik
la source
Les liens tinypiques sont rompus.
ANeves
11

D'après ce que je comprends, l'intention d'utiliser l'élément <exception> est de l'utiliser lors de la décoration de méthodes, pas d'exceptions:

/// <summary>Does something!</summary>
/// <exception cref="DidNothingException">Thrown if nothing is actually done.</exception>
public void DoSomething()
{
// There be logic here
}

Les exceptions qui peuvent être levées par d'autres méthodes appelées doivent être interceptées, gérées et documentées dans ces méthodes. Les exceptions qui pourraient éventuellement être levées par .NET ou celles qui sont explicitement levées par votre propre code doivent être documentées.

En ce qui concerne plus de précision que cela, vous pouvez peut-être attraper et lancer vos propres exceptions personnalisées?

Daniel Schaffer
la source
4

Une partie du contrat pour votre méthode devrait être de vérifier que les conditions préalables sont valides, donc:

public void MyMethod2()
{
    System.IO.File.Open(somepath...); // this may throw FileNotFoundException
}

devient

/// <exception cref="FileNotFoundException">Thrown when somepath isn't a real file.</exception>
public void MyMethod2()
{
    FileInfo fi = new FileInfo( somepath );
    if( !fi.Exists )
    {
        throw new FileNotFoundException("somepath doesn't exists")
    }
    // Maybe go on to check you have permissions to read from it.

    System.IO.File.Open(somepath...); // this may still throw FileNotFoundException though
}

Avec cette approche, il est plus facile de documenter toutes les exceptions que vous lancez explicitement sans avoir à documenter également le fait qu'un a OutOfMemoryException peut être levé, etc.

Rowland Shaw
la source
1
Je ne sais pas à quoi sert cette vérification si vous allez simplement dupliquer l'exception que l' Openappel lancerait de toute façon (sans oublier, comme vous le notez, qu'il y a une course et que la vérification ne garantit pas le succès de Open). .
Matt Enright
1
@MattEnright Accordé, mais je l'ai fait un peu artificiel pour illustrer le point ...
Rowland Shaw
1

Vous devez documenter toutes les exceptions qui pourraient éventuellement être levées par votre méthode.

Pour masquer les détails de l'implémentation, j'essaierais de gérer moi-même certaines exceptions de MyMethod2.

Vous pouvez envisager de les récupérer si vous ne pouvez pas gérer ou résoudre l'exception. Principalement emballé / enveloppé dans une exception plus significative pour l'appelant.

GvS
la source
1

En effet, comme il a déjà été répondu, la manière de documenter les exceptions est d'utiliser des commentaires XML.

En plus des plugins, vous pouvez également utiliser des outils d'analyse statique qui peuvent être intégrés à TFS pour vous assurer que les exceptions sont documentées.

Dans les liens ci-dessous, vous pouvez voir comment créer une règle personnalisée pour que StyleCop valide les exceptions levées par vos méthodes sont documentées.

http://www.josefcobonnin.com/post/2009/01/11/Xml-Documentation-Comments-Exceptions-I.aspx http://www.josefcobonnin.com/post/2009/01/15/Xml-Documentation -Commentaires-Exceptions-II.aspx

Cordialement.


la source
0

Documentez les exceptions attendues dans votre méthode, dans votre exemple, je ferais savoir à l'utilisateur que cette méthode peut lancer une exception de fichier non trouvé.

N'oubliez pas qu'il s'agit d'informer l'appelant de ce à quoi il doit s'attendre afin qu'il puisse choisir comment y faire face.

Damien
la source