XML-Dokumentationskommentare

C#-Quelldateien können strukturierte Kommentare enthalten, die API-Dokumentation für die in diesen Dateien definierten Typen erzeugen. Der C#-Compiler erzeugt eine XML-Datei, die strukturierte Daten enthält, die die Kommentare und API-Signaturen darstellen. Andere Tools können diese XML-Ausgabe verarbeiten, um beispielsweise eine lesbare Dokumentation in Form von Webseiten oder PDF-Dateien zu erstellen.

Dieser Prozess bietet viele Vorteile für das Hinzufügen von API-Dokumentation in Ihrem Code:

  • Der C#-Compiler kombiniert die Struktur des C#-Codes mit dem Text der Kommentare in einem einzelnen XML-Dokument.
  • Der C#-Compiler überprüft, ob die Kommentare mit den API-Signaturen für relevante Tags übereinstimmen.
  • Tools, die die XML-Dokumentationsdateien verarbeiten, können XML-Elemente und -Attribute definieren, die für diese Tools spezifisch sind.

Tools wie Visual Studio bieten IntelliSense für viele allgemeine XML-Elemente, die in Dokumentationskommentaren verwendet werden.

In diesem Artikel werden folgende Themen erörtert:

  • Dokumentationskommentare und Generierung von XML-Dateien
  • Vom C#-Compiler und Visual Studio überprüfte Tags
  • Format der generierten XML-Datei

Erstellen der XML-Dokumentationsausgabe

Sie erstellen die Dokumentation für Ihren Code, indem Sie spezielle Kommentarfelder schreiben, die durch dreifache Schrägstriche gekennzeichnet sind (///). Die Kommentarfelder enthalten XML-Elemente, die den Codeblock beschreiben, der den Kommentaren folgt. Beispiel:

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

Sie legen die Option GenerateDocumentationFile oder DocumentationFile fest, und der Compiler findet alle Kommentarfelder mit XML-Tags im Quellcode und erstellt aus diesen Kommentaren eine XML-Dokumentationsdatei. Wenn diese Option aktiviert ist, generiert der Compiler die Warnung CS1591 für alle öffentlich sichtbaren Member, die in Ihrem Projekt ohne XML-Dokumentationskommentare deklariert sind.

XML-Kommentarformate

Die Verwendung von XML-Dokumentationskommentaren erfordert Trennzeichen, die angeben, wo ein Dokumentationskommentar beginnt und endet. Sie können die folgenden Arten von Trennzeichen mit den XML-Dokumentationstags verwenden:

  • /// Einzeiliges Trennzeichen: Dieses wird in den Dokumentationsbeispielen und C#-Projektvorlagen verwendet. Wenn dem Trennzeichen Leerzeichen folgen, wird es nicht in die XML-Ausgabe aufgenommen.

    Hinweis

    Visual Studio fügt die Tags <summary> und </summary> automatisch ein und positioniert den Cursor innerhalb dieser Tags, nachdem Sie das Trennzeichen /// in den Code-Editor eingefügt haben. Sie können diese Funktion im Dialogfeld „Optionen“ aktivieren oder deaktivieren.

  • /** */ Mehrzeilige Trennzeichen: Für die /** */-Trennzeichen gelten die folgenden Formatierungsregeln:
    • In der Zeile mit dem /**-Trennzeichen, wenn der Rest der Zeile Leerraum ist, wird die Zeile für Kommentare nicht verarbeitet. Wenn das erste Zeichen nach dem /**-Trennzeichen ein Leerzeichen ist, wird dieses Leerzeichen ignoriert und der Rest der Zeile verarbeitet. Andernfalls wird de gesamte Text der Zeile nach dem /**-Trennzeichen als Teil des Kommentars verarbeitet.

    • In der Zeile mit dem */-Trennzeichen, wenn sie nur aus Leerzeichen bis zum */-Trennzeichen besteht, wird diese Zeile ignoriert. Andernfalls wird der Text der Zeile bis zum */-Trennzeichen als Teil des Kommentars verarbeitet.

    • Für die Zeilen nach der, die mit dem /**-Trennzeichen beginnt, sucht der Compiler ein gemeinsames Muster am Anfang jeder Zeile. Das Muster kann aus optionalen Leerzeichen und einem Sternchen bestehen (*), gefolgt von weiteren optionalen Leerzeichen. Wenn der Compiler am Anfang jeder Zeile ein gemeinsames Muster findet, die nicht mit dem /**- oder */-Trennzeichen beginnt oder endet, ignoriert er dieses Muster für jede Zeile.

    • Der einzige Teil des folgenden Kommentars, der verarbeitet wird, ist die Zeile, die mit <summary> beginnt. Die drei Tag-Formate ergeben identische Kommentare.

      /** <summary>text</summary> */
      
      /**
      <summary>text</summary>
      */
      
      /**
      * <summary>text</summary>
      */
      
    • Der Compiler identifiziert ein gemeinsames Muster von „*“ am Anfang der zweiten und dritten Zeile. Das Muster ist nicht in der Ausgabe enthalten.

      /**
      * <summary>
      * text </summary>*/
      
    • Der Compiler findet kein gemeinsames Muster im folgenden Kommentar, da das zweite Zeichen in der dritten Zeile kein Sternchen ist. Der gesamte Text wird in der zweiten und dritten Zeile als Teil des Kommentars verarbeitet.

      /**
      * <summary>
         text </summary>
      */
      
    • Der Compiler findet aus zwei Gründen kein Muster im folgenden Kommentar. Erstens ist die Anzahl von Leerzeichen vor dem Sternchen nicht konsistent. Zweitens beginnt die fünfte Zeile mit einem Tab, der mit Leerzeichen nicht übereinstimmt. Der gesamte Text wird von Zeile zwei bis fünf als Teil des Kommentars verarbeitet.

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

Zum Verweisen auf XML-Elemente (beispielsweise verarbeitet eine Funktion bestimmte XML-Elemente, die Sie in einem XML-Dokumentationskommentar beschreiben möchten) können Sie die Standardnotierungsart verwenden (&lt; und &gt;). Zum Verweisen auf generische Bezeichner in Codeverweiselementen (cref-Elementen) können Sie entweder die Escapezeichen (z.B. cref="List&lt;T&gt;") oder geschweifte Klammern (cref="List{T}") verwenden. Als Sonderfall analysiert der Compiler die geschweiften Klammern als spitze Klammern, um das Erstellen des Dokumentationskommentars beim Verweisen auf generische Bezeichner weniger schwerfällig zu gestalten.

Hinweis

XML-Dokumentationskommentare sind keine Metadaten und sind nicht in der kompilierten Assembly enthalten. Folglich ist der Zugriff auf sie über Reflektion nicht möglich.

Tools, die XML-Dokumentationseingaben akzeptieren

Die folgenden Tools erstellen die Ausgabe aus XML-Kommentaren:

  • DocFX:DocFX ist ein API-Dokumentations-Generator für .NET, der derzeit C#, Visual Basic und F# unterstützt. Außerdem können Sie damit die generierte Referenzdokumentation anpassen. DocFX erstellt eine statische HTML-Website aus Ihrem Quellcode und Ihren Markdowndateien. Darüber hinaus bietet DocFX Ihnen die Flexibilität, das Layout und das Format Ihrer Website über Vorlagen anzupassen. Sie können auch benutzerdefinierte Vorlagen erstellen.
  • Sandcastle: Die Sandcastle-Tools erstellen Hilfedateien für verwaltete Klassenbibliotheken, die sowohl konzeptionelle Seiten als auch API-Referenzseiten enthalten. Die Sandcastle-Tools sind befehlszeilenbasierte Tools und verfügen nicht über GUI-Front-End, Projektverwaltungsfeatures oder einen automatisierten Buildprozess. Der Sandcastle Help File Builder stellt eine eigenständige GUI und Befehlszeilentools zum automatisierten Erstellen einer Hilfedatei zur Verfügung. Ein Visual Studio-Integrationspaket ist auch verfügbar, sodass Hilfeprojekte vollständig innerhalb von Visual Studio erstellt und verwaltet werden können.
  • Doxygen:Doxygen generiert einen Onlinedokumentationsbrowser (in HTML) oder ein Offlinereferenzhandbuch (in LaTeX) aus einer Reihe dokumentierter Quelldateien. Zusätzlich ist Unterstützung für das Generieren von Ausgaben in RTF (MS Word), PostScript, PDF als Hyperlink, komprimierte HTML, DocBook und Unix-Manpages verfügbar. Sie können Doxygen so konfigurieren, dass die Codestruktur aus nicht dokumentierten Quelldateien extrahiert wird.

ID-Zeichenfolgen

Jeder Typ oder Member wird in einem Element in der XML-Ausgabedatei gespeichert. Jedes dieser Elemente verfügt über eine eindeutige ID-Zeichenfolge, die den Typ oder Member identifiziert. Die ID-Zeichenfolge muss Operatoren, Parameter, Rückgabewerte, generische Typparameter, ref, in und out-Parameter nachweisen. Der Compiler folgt klar definierten Regeln zum Generieren der ID-Zeichenfolgen, um alle potenziellen Elemente zu codieren. Programme, die die XML-Datei verarbeiten, können mithilfe der ID-Zeichenfolge das entsprechende .NET-Metadatenelement oder -Reflektionselement identifizieren, für das die Dokumentation gilt.

Der Compiler beachtet beim Generieren der ID-Zeichenfolgen die folgenden Regeln:

  • Es befindet sich kein Leerraum in der Zeichenfolge.

  • Der erste Teil der Zeichenfolge kennzeichnet die Art des Members durch ein einzelnes Zeichen, dem ein Doppelpunkt folgt. Die folgenden Membertypen werden verwendet:

    Zeichen Memberart Hinweise
    N namespace Einem Namespace können keine Dokumentationskommentare hinzugefügt werden. Falls unterstützt, können jedoch cref-Verweise hinzugefügt werden.
    T Typ Ein Typ ist eine Klasse, eine Schnittstelle, eine Struktur, eine Enumeration oder ein Delegat.
    F Feld
    P property Schließt Indexer und andere indizierte Eigenschaften ein
    M Methode Schließt spezielle Methoden wie Konstruktoren und Operatoren ein
    E event
    ! Fehlerzeichenfolge Der verbleibende Teil der Zeichenfolge enthält Fehlerinformationen. Vom C#-Compiler werden Fehlerinformationen für Links erstellt, die nicht aufgelöst werden können.
  • Beim zweiten Teil der Zeichenfolge handelt es sich um den vollqualifizierten Namen eines Elements, beginnend mit dem Namespace-Stammverzeichnis. Der Name des Elements, der oder die einschließenden Typen und der Namespace sind durch Punkte getrennt. Wenn der Name des Elements selbst Punkte enthält, werden sie durch ein Rautezeichen (#) ersetzt. Es wird vorausgesetzt, dass kein Element direkt im Namen ein Rautezeichen enthält. Der vollqualifizierte Name des String-Konstruktors lautet beispielsweise „System.String.#ctor“.

  • Bei Eigenschaften und Methoden folgt die in Klammern eingeschlossene Parameterliste. Wenn keine Parameter vorhanden sind, werden keine Klammern verwendet. Die Parameter werden durch Kommas voneinander getrennt. Die Codierung jedes Parameters erfolgt direkt wie bei einer .NET-Signatur (Definitionen des Elements in Großbuchstaben finden Sie unter Microsoft.VisualStudio.CorDebugInterop.CorElementType in der folgenden Liste):

    • Basistypen. Reguläre Typen (ELEMENT_TYPE_CLASS oder ELEMENT_TYPE_VALUETYPE) werden als vollqualifizierter Name des Typs dargestellt.
    • Systeminterne Typen (zum Beispiel ELEMENT_TYPE_I4, ELEMENT_TYPE_OBJECT, ELEMENT_TYPE_STRING, ELEMENT_TYPE_TYPEDBYREF und ELEMENT_TYPE_VOID) werden als vollqualifizierter Name des entsprechenden vollständigen Typs dargestellt. Zum Beispiel: System.Int32 oder System.TypedReference.
    • ELEMENT_TYPE_PTR wird als „*“ hinter dem geänderten Typ dargestellt.
    • ELEMENT_TYPE_BYREF wird als „@“ hinter dem geänderten Typ dargestellt.
    • ELEMENT_TYPE_CMOD_OPT wird als „!“ mit nachstehendem vollqualifizierten Namen der Modifiziererklasse dargestellt, das auf den geänderten Typ folgt.
    • ELEMENT_TYPE_SZARRAY wird als „[]“ dargestellt, das auf den Elementtyp des Arrays folgt.
    • ELEMENT_TYPE_ARRAY wird als [lowerbound:size,lowerbound:size] dargestellt, wobei die Anzahl von Kommas als Rang minus 1 berechnet wird und die untere Grenze sowie die Größe jeder Dimension – sofern bekannt – dezimal dargestellt werden. Wenn die untere Grenze oder die Größe nicht angegeben ist, wird sie ausgelassen. Wenn die untere Grenze und die Größe für eine bestimmte Dimension ausgelassen werden, kann der Doppelpunkt (:) ebenfalls ausgelassen werden. [1:,1:] ist beispielsweise ein zweidimensionales Array mit 1 als unterer Grenze und nicht angegebenen Größen.
  • Nur für Konvertierungsoperatoren (op_Implicit und op_Explicit) wird der Rückgabewert der Methode als „~“ gefolgt vom Rückgabewert codiert. Beispiel: <member name="M:System.Decimal.op_Explicit(System.Decimal arg)~System.Int32"> ist das Tag für den in der System.Decimal-Klasse deklarierten Umwandlungsoperator public static explicit operator int (decimal value);.

  • Bei generischen Typen folgt auf den Namen des Typs ein Graviszeichen und dann eine Zahl, mit der die Anzahl generischer Typparameter angegeben wird. Beispiel: <member name="T:SampleClass``2"> ist das Tag für einen Typ, der als public class SampleClass<T, U> definiert ist. Bei Methoden, die generische Typen als Parameter verwenden, werden die generischen Parameter des Typs als Zahlen mit vorangestelltem Backticks angegeben (z. B. `0,`1). Jede Zahl stellt eine bei 0 beginnende Arraynotation für die generischen Parameter des Typs dar.

    • ELEMENT_TYPE_PINNED wird als „^“ dargestellt, das auf den geänderten Typ folgt. Diese Codierung wird nie vom C#-Compiler generiert.
    • ELEMENT_TYPE_CMOD_REQ wird als „|“ und dem vollqualifizierten Namen der Modifiziererklasse hinter dem geänderten Typ dargestellt. Diese Codierung wird nie vom C#-Compiler generiert.
    • ELEMENT_TYPE_GENERICARRAY wird als „[?]“ dargestellt, das auf den Elementtyp des Arrays folgt. Diese Codierung wird nie vom C#-Compiler generiert.
    • ELEMENT_TYPE_FNPTR wird als „=FUNC:type(signature)“ dargestellt, wobei type den Rückgabetyp angibt und es sich bei signature um die Argumente der Methode handelt. Sind keine Argumente vorhanden, werden keine Klammern verwendet. Diese Codierung wird nie vom C#-Compiler generiert.
    • Die folgenden Signaturkomponenten werden nicht dargestellt, weil sie nicht zur Unterscheidung überladener Methoden verwendet werden:
      • Aufrufkonvention
      • Rückgabetyp
      • ELEMENT_TYPE_SENTINEL

In den folgenden Beispielen wird veranschaulicht, wie die ID-Zeichenfolgen für eine Klasse und ihre Member generiert werden:

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; }
    }
}

C#-Sprachspezifikation

Weitere Informationen finden Sie im Anhang der C#-Sprachspezifikation zu Dokumentationskommentaren.