Commentaires sur la documentation XML

Les fichiers sources C# peuvent avoir des commentaires structurés qui produisent une documentation d’API pour les types définis dans ces fichiers. Le compilateur C# produit un fichier XML qui contient des données structurées représentant les commentaires et les signatures d’API. D’autres outils peuvent traiter cette sortie XML pour créer une documentation lisible par l’homme sous la forme de pages web ou de fichiers PDF, par exemple.

Ce processus offre de nombreux avantages et vous permet d’ajouter de la documentation d’API dans votre code :

  • Le compilateur C# combine la structure du code C# avec le texte des commentaires dans un document XML unique.
  • Le compilateur C# vérifie que les commentaires correspondent aux signatures d’API pour les balises pertinentes.
  • Les outils qui traitent les fichiers de documentation XML peuvent définir des éléments et des attributs XML spécifiques à ces outils.

Les outils tels que Visual Studio fournissent IntelliSense pour de nombreux éléments XML courants utilisés dans les commentaires de documentation.

Cet article traite des sujets suivants :

  • Commentaires de documentation et génération de fichiers XML
  • Balises validées par le compilateur C# et Visual Studio
  • Format du fichier XML généré

Créer une sortie de documentation XML

Vous créez la documentation pour votre code en écrivant des champs de commentaire spéciaux indiqués par trois barres obliques. Les champs de commentaire incluent des éléments XML qui décrivent le bloc de code qui suit les commentaires. Par exemple :

/// <summary>
///  This class performs an important function.
/// </summary>
public class MyClass {}

Vous définissez l’option GenerateDocumentationFile ou DocumentationFile, et le compilateur recherche tous les champs de commentaire avec des balises XML dans le code source et crée un fichier de documentation XML à partir de ces commentaires. Quand cette option est activée, le compilateur génère l’avertissement CS1591 pour tout membre publiquement visible déclaré dans votre projet sans commentaires de documentation XML.

Formats de commentaire XML

L’utilisation de commentaires de documentation XML exige des délimiteurs, qui indiquent où un commentaire de documentation commence et se termine. Vous utilisez les délimiteurs suivants avec les balises de documentation XML :

  • Délimiteur à ligne unique /// : les exemples de documentation et les modèles de projet C# utilisent cette forme. Si un espace blanc suit ce délimiteur, il n’est pas inclus dans la sortie XML.

    Notes

    Visual Studio insère automatiquement les balises <summary> et </summary>, et positionne votre curseur dans ces balises une fois que vous avez tapé le délimiteur /// dans l’éditeur de code. Vous pouvez activer/désactiver cette fonctionnalité dans la boîte de dialogue Options.

  • Délimiteurs multilignes /** */ : les délimiteurs /** */ ont les règles de mise en forme suivantes :
    • Sur la ligne qui contient le délimiteur /**, si le reste de la ligne est constitué d’espaces blancs, la ligne n’est pas traitée pour les commentaires. Si le premier caractère après le délimiteur /** est un espace blanc, celui-ci est ignoré et le reste de la ligne est traité. Sinon, tout le texte de la ligne après le délimiteur /** est traité comme faisant partie du commentaire.

    • Sur la ligne qui contient le délimiteur */, s’il n’y a que des espaces blancs jusqu’au délimiteur */, la ligne est ignorée. Sinon, le texte de la ligne jusqu’au délimiteur */ est traité comme faisant partie du commentaire.

    • Pour les lignes situées après celle qui commence par le délimiteur /**, le compilateur recherche un modèle commun au début de chaque ligne. Le modèle peut se composer d’un espace blanc facultatif et d’un astérisque (*), suivi d’autres espaces blancs facultatifs. Si le compilateur détecte un modèle commun au début de chaque ligne qui ne commence pas par le délimiteur /** ou qui ne finit pas par le délimiteur */, il ignore ce modèle pour chaque ligne.

    • La seule partie du commentaire suivant qui sera traitée est la ligne qui commence par <summary>. Les trois formats de balise produisent les mêmes commentaires.

      /** <summary>text</summary> */
      
      /**
      <summary>text</summary>
      */
      
      /**
      * <summary>text</summary>
      */
      
    • Le compilateur identifie un modèle commun « * » au début des deuxième et troisième lignes. Le modèle n’est pas inclus dans la sortie.

      /**
      * <summary>
      * text </summary>*/
      
    • Le compilateur ne détecte aucun modèle commun dans le commentaire suivant, car le deuxième caractère sur la troisième ligne n’est pas un astérisque. Tout le texte des deuxième et troisième lignes est traité comme faisant partie du commentaire.

      /**
      * <summary>
         text </summary>
      */
      
    • Le compilateur ne détecte aucun modèle dans le commentaire suivant pour deux raisons. Tout d’abord, le nombre d’espaces avant l’astérisque n’est pas constant. Ensuite, la cinquième ligne commence par une tabulation, qui ne correspond pas à des espaces. Tout le texte des lignes 2 à 5 est traité comme faisant partie du commentaire.

      /**
        * <summary>
        * text
      *  text2
       	*  </summary>
      */
      

Pour faire référence à des éléments XML (par exemple, votre fonction traite des éléments XML spécifiques que vous souhaitez décrire dans un commentaire de documentation XML), vous pouvez utiliser le mécanisme de citation standard (&lt; et &gt;). Pour faire référence aux identificateurs génériques dans les éléments de référence de code (cref), vous pouvez utiliser des caractères d’échappement (par exemple, cref="List&lt;T&gt;") ou des accolades (cref="List{T}"). En tant que cas particulier, le compilateur analyse les accolades comme des crochets pointus pour rendre le commentaire de documentation moins fastidieux à créer lorsqu'il s'agit de faire référence aux identificateurs génériques.

Notes

Les commentaires de documentation XML ne sont pas des métadonnées. Ils ne sont pas inclus dans l'assembly compilé et ne sont donc pas accessibles par réflexion.

Outils qui acceptent l’entrée de documentation XML

Les outils suivants créent une sortie à partir de commentaires XML :

  • DocFX : DocFX est un générateur de documentation d’API pour .NET, qui prend actuellement en charge C#, Visual Basic et F#. Il vous permet également de personnaliser la documentation de référence générée. DocFX génère un site web HTML statique à partir de votre code source et de vos fichiers Markdown. DocFX vous offre également la possibilité de personnaliser la mise en page et le style de votre site web à l’aide de modèles. Vous pouvez également créer des modèles personnalisés.
  • Sandcastle : les outils Sandcastle créent des fichiers d’aide pour les bibliothèques de classes managées contenant à la fois des pages de référence sur les concepts et les API. Les outils Sandcastle sont basés sur la ligne de commande et ne disposent d’aucune interface utilisateur graphique frontale, d’aucune fonctionnalité de gestion de projet ni d’aucun processus de génération automatisé. Sandcastle Help File Builder fournit une interface utilisateur graphique autonome et des outils basés sur la ligne de commande pour créer un fichier d’aide de manière automatisée. Un package d’intégration Visual Studio est également disponible pour cela afin que les projets d’aide puissent être créés et gérés entièrement depuis Visual Studio.
  • Doxygen : Doxygen génère un navigateur de documentation en ligne (en HTML) ou un manuel de référence hors ligne (dans LaTeX) à partir d’un ensemble de fichiers sources documentés. Il existe également une prise en charge de la génération d’une sortie dans les pages de manuel RTF (MS Word), PostScript, PDF avec lien hypertexte, HTML compressé, DocBook et Unix. Vous pouvez configurer Doxygen pour extraire la structure du code à partir de fichiers sources non documentés.

Chaînes d’ID

Chaque type ou membre est stocké dans un élément dans le fichier XML de sortie. Chacun de ces éléments a une chaîne d’ID unique qui identifie le type ou le membre. La chaîne d’ID doit prendre en compte les opérateurs, les paramètres, les valeurs de retour, les paramètres de type générique et les paramètres ref, in et out. Pour encoder tous ces éléments potentiels, le compilateur suit des règles clairement définies pour générer les chaînes d’ID. Les programmes qui traitent le fichier XML utilisent la chaîne d’ID pour identifier l’élément de métadonnées ou de réflexion .NET correspondant auquel s’applique la documentation.

Le compilateur respecte les règles suivantes quand il génère les chaînes d’ID :

  • La chaîne ne contient aucun espace blanc.

  • La première partie de cette chaîne identifie le type de membre avec un caractère unique suivi d’un signe deux-points. Les types de membres suivants sont utilisés :

    Caractère Type de membre Notes
    N espace de noms Vous ne pouvez pas ajouter de commentaires de documentation à un espace de noms, mais vous pouvez insérer des références cref à des commentaires, là où cela est pris en charge.
    T type Un type est une classe, une interface, un struct, une énumération ou un délégué.
    F field
    P propriété Inclut des indexeurs ou d’autres propriétés indexées.
    M method Inclut des méthodes spéciales, telles que des constructeurs et des opérateurs.
    E événement
    ! chaîne d’erreur Le reste de la chaîne fournit des informations sur l’erreur. Le compilateur C# génère des informations d’erreur pour les liens qui ne peuvent pas être résolus.
  • La deuxième partie de la chaîne est le nom qualifié complet de l’élément, en commençant à la racine de l’espace de noms. Le nom de l’élément, ses types englobants et l’espace de noms sont séparés par des points. Si le nom de l’élément lui-même comporte des points, ceux-ci sont remplacés par un signe dièse (« # »). Il est supposé qu’aucun élément n’a de signe dièse directement dans son nom. Par exemple, le nom complet du constructeur String est « System.String.#ctor ».

  • Pour les propriétés et les méthodes, la liste de paramètres entre parenthèses suit. S’il n’y a pas de paramètres, les parenthèses ne sont pas présentes. Les paramètres sont séparés par des virgules. L’encodage de chaque paramètre suit directement la façon dont il est encodé dans une signature .NET (consultez Microsoft.VisualStudio.CorDebugInterop.CorElementType pour obtenir les définitions des éléments en majuscules listés ci-dessous) :

    • Types de base. Les types réguliers (ELEMENT_TYPE_CLASS ou ELEMENT_TYPE_VALUETYPE) sont représentés en tant que nom complet du type.
    • Les types intrinsèques (par exemple, ELEMENT_TYPE_I4, ELEMENT_TYPE_OBJECT, ELEMENT_TYPE_STRING, ELEMENT_TYPE_TYPEDBYREF et ELEMENT_TYPE_VOID) sont représentés en tant que nom complet du type complet correspondant. Par exemple, System.Int32 ou System.TypedReference.
    • ELEMENT_TYPE_PTR est représenté par un « * » après le type modifié.
    • ELEMENT_TYPE_BYREF est représenté par un « @ » après le type modifié.
    • ELEMENT_TYPE_CMOD_OPT est représenté par un « ! » et le nom complet de la classe de modificateur, après le type modifié.
    • ELEMENT_TYPE_SZARRAY est représenté par « [] » après le type d’élément du tableau.
    • ELEMENT_TYPE_ARRAY est représenté par [limite_inférieure:size,limite_inférieure:size], où le nombre de virgules correspond au rang – 1, et les limites inférieures et la taille de chaque dimension, si elles sont connues, sont représentées sous forme décimale. Si une limite inférieure ou une taille n’est pas spécifiée, elle est omise. Si la limite inférieure et la taille d’une dimension particulière sont omises, le « : » est également omis. Par exemple, un tableau à deux dimensions avec 1 comme limites inférieures et des tailles non spécifiées est représenté par [1:,1:].
  • Pour les opérateurs de conversion uniquement (op_Implicit et op_Explicit), la valeur de retour de la méthode est encodée par un ~, suivi du type de retour. Par exemple : <member name="M:System.Decimal.op_Explicit(System.Decimal arg)~System.Int32"> est la balise de l’opérateur de cast public static explicit operator int (decimal value); déclaré dans la classe System.Decimal.

  • Pour les types génériques, le nom du type est suivi d’un accent grave, puis d’un chiffre qui indique le nombre de paramètres de type générique. Par exemple : <member name="T:SampleClass``2"> est la balise pour un type qui est défini en tant que public class SampleClass<T, U>. Pour les méthodes qui prennent des types génériques comme paramètres, les paramètres de types génériques sont spécifiés sous forme de nombres précédés d’accents graves (par exemple `0,`1). Chaque nombre représente une notation de tableau de base zéro pour les paramètres génériques du type.

    • ELEMENT_TYPE_PINNED est représenté par un « ^ » après le type modifié. Le compilateur C# ne génère jamais ce codage.
    • ELEMENT_TYPE_CMOD_REQ est représenté par un « | » et le nom complet de la classe de modificateur, après le type modifié. Le compilateur C# ne génère jamais ce codage.
    • ELEMENT_TYPE_GENERICARRAY est représenté par « [?] » après le type d’élément du tableau. Le compilateur C# ne génère jamais ce codage.
    • ELEMENT_TYPE_FNPTR est représenté par « =FUNC:type(signature) », où type est le type de retour et signature correspond aux arguments de la méthode. S’il n’y a pas d’argument, les parenthèses sont omises. Le compilateur C# ne génère jamais ce codage.
    • Les composants de signature suivants ne sont pas représentés, car ils ne sont pas utilisés pour différencier les méthodes surchargées :
      • convention d’appel
      • type de retour
      • ELEMENT_TYPE_SENTINEL

Les exemples suivants montrent comment les chaînes d’ID pour une classe et ses membres sont générées :

namespace MyNamespace
{
    /// <summary>
    /// Enter description here for class X.
    /// ID string generated is "T:MyNamespace.MyClass".
    /// </summary>
    public unsafe class MyClass
    {
        /// <summary>
        /// Enter description here for the first constructor.
        /// ID string generated is "M:MyNamespace.MyClass.#ctor".
        /// </summary>
        public MyClass() { }

        /// <summary>
        /// Enter description here for the second constructor.
        /// ID string generated is "M:MyNamespace.MyClass.#ctor(System.Int32)".
        /// </summary>
        /// <param name="i">Describe parameter.</param>
        public MyClass(int i) { }

        /// <summary>
        /// Enter description here for field message.
        /// ID string generated is "F:MyNamespace.MyClass.message".
        /// </summary>
        public string? message;

        /// <summary>
        /// Enter description for constant PI.
        /// ID string generated is "F:MyNamespace.MyClass.PI".
        /// </summary>
        public const double PI = 3.14;

        /// <summary>
        /// Enter description for method func.
        /// ID string generated is "M:MyNamespace.MyClass.func".
        /// </summary>
        /// <returns>Describe return value.</returns>
        public int func() { return 1; }

        /// <summary>
        /// Enter description for method someMethod.
        /// ID string generated is "M:MyNamespace.MyClass.someMethod(System.String,System.Int32@,System.Void*)".
        /// </summary>
        /// <param name="str">Describe parameter.</param>
        /// <param name="num">Describe parameter.</param>
        /// <param name="ptr">Describe parameter.</param>
        /// <returns>Describe return value.</returns>
        public int someMethod(string str, ref int nm, void* ptr) { return 1; }

        /// <summary>
        /// Enter description for method anotherMethod.
        /// ID string generated is "M:MyNamespace.MyClass.anotherMethod(System.Int16[],System.Int32[0:,0:])".
        /// </summary>
        /// <param name="array1">Describe parameter.</param>
        /// <param name="array">Describe parameter.</param>
        /// <returns>Describe return value.</returns>
        public int anotherMethod(short[] array1, int[,] array) { return 0; }

        /// <summary>
        /// Enter description for operator.
        /// ID string generated is "M:MyNamespace.MyClass.op_Addition(MyNamespace.MyClass,MyNamespace.MyClass)".
        /// </summary>
        /// <param name="first">Describe parameter.</param>
        /// <param name="second">Describe parameter.</param>
        /// <returns>Describe return value.</returns>
        public static MyClass operator +(MyClass first, MyClass second) { return first; }

        /// <summary>
        /// Enter description for property.
        /// ID string generated is "P:MyNamespace.MyClass.prop".
        /// </summary>
        public int prop { get { return 1; } set { } }

        /// <summary>
        /// Enter description for event.
        /// ID string generated is "E:MyNamespace.MyClass.OnHappened".
        /// </summary>
        public event Del? OnHappened;

        /// <summary>
        /// Enter description for index.
        /// ID string generated is "P:MyNamespace.MyClass.Item(System.String)".
        /// </summary>
        /// <param name="str">Describe parameter.</param>
        /// <returns></returns>
        public int this[string s] { get { return 1; } }

        /// <summary>
        /// Enter description for class Nested.
        /// ID string generated is "T:MyNamespace.MyClass.Nested".
        /// </summary>
        public class Nested { }

        /// <summary>
        /// Enter description for delegate.
        /// ID string generated is "T:MyNamespace.MyClass.Del".
        /// </summary>
        /// <param name="i">Describe parameter.</param>
        public delegate void Del(int i);

        /// <summary>
        /// Enter description for operator.
        /// ID string generated is "M:MyNamespace.MyClass.op_Explicit(MyNamespace.MyClass)~System.Int32".
        /// </summary>
        /// <param name="myParameter">Describe parameter.</param>
        /// <returns>Describe return value.</returns>
        public static explicit operator int(MyClass myParameter) { return 1; }
    }
}

spécification du langage C#

Pour plus d’informations, consultez l’annexe Spécification du langage C# sur les commentaires de documentation.