Freigeben über


Anhang D Anmerkungen zur Dokumentation

Dieser Anhang ist informativ.

D.1 Allgemeines

C# bietet einen Mechanismus, mit dem Programmierer ihren Code mit einer Kommentarsyntax dokumentieren können, die XML-Text enthält. In Quellcodedateien können Kommentare in einer bestimmten Form verwendet werden, um ein Tool anzuweisen, XML aus diesen Kommentaren und den ihnen vorangestellten Quellcodeelementen zu erzeugen. Kommentare mit einer solchen Syntax werden Dokumentationskommentaregenannt. Sie müssen unmittelbar vor einem benutzerdefinierten Typ (z. B. einer Klasse, einem Delegaten oder einer Schnittstelle) oder einem Mitglied (z. B. einem Feld, Ereignis, einer Eigenschaft oder einer Methode) stehen. Das XML-Generierungswerkzeug heißt Dokumentationsgenerator. (Dieser Generator kann, muss aber nicht, der C#-Compiler selbst sein.) Die vom Dokumentationsgenerator erzeugte Ausgabe wird Dokumentationsdateigenannt. Eine Dokumentationsdatei wird als Eingabe für einen Dokumentationsbetrachterverwendet. Dabei handelt es sich um ein Werkzeug, das eine Art visuelle Darstellung von Typinformationen und der dazugehörigen Dokumentation erzeugen soll.

Ein konformer C#-Compiler ist nicht verpflichtet, die Syntax von Dokumentationskommentaren zu prüfen; solche Kommentare sind einfach gewöhnliche Kommentare. Ein konformer Compiler darf jedoch eine solche Prüfung durchführen.

Diese Spezifikation schlägt eine Reihe von Standard-Tags vor, die in Dokumentationskommentaren verwendet werden können. Die Verwendung dieser Tags ist jedoch nicht vorgeschrieben, und es können auch andere Tags verwendet werden, solange die Regeln für wohlgeformtes XML eingehalten werden. Für C#-Implementierungen, die auf die CLI abzielen, finden Sie hier auch Informationen über den Dokumentationsgenerator und das Format der Dokumentationsdatei. Es werden keine Informationen über den Dokumentationsbetrachter bereitgestellt.

D.2 Einleitung

Kommentare, die eine bestimmte Form haben, können verwendet werden, um ein Tool anzuweisen, XML aus diesen Kommentaren und den ihnen vorangestellten Quellcodeelementen zu erzeugen. Solche Kommentare sind Single_Line_Comments (§6.3.3), die mit drei Schrägstrichen beginnen (///), oder Delimited_Comments (§6.3.3), die mit einem Schrägstrich und zwei Sternchen beginnen (/**). Sie müssen unmittelbar vor einem benutzerdefinierten Typ oder einem Member stehen, den sie annotieren. Attributabschnitte (§22.3) werden als Teil von Deklarationen betrachtet, so dass Dokumentationskommentare vor Attributen stehen müssen, die auf einen Typ oder ein Member angewendet werden.

Zur Veranschaulichung wird das Format der Dokumentenkommentare im Folgenden als zwei Grammatikregeln dargestellt: Single_Line_Doc_Comment und Delimited_Doc_Comment. Diese Regeln sind jedoch nicht Teil der C#-Grammatik, sondern repräsentieren bestimmte Formate von Single_Line_Comment bzw. Delimited_Comment Lexer-Regeln.

Syntax:

Single_Line_Doc_Comment
    : '///' Input_Character*
    ;
   
Delimited_Doc_Comment
    : '/**' Delimited_Comment_Section* ASTERISK+ '/'
    ;

Wenn in einem Single_Line_Doc_Commentein Leer -zeichen nach den /// -Zeichen in jedem der Single_Line_Doc_Comments neben dem aktuellen Single_Line_Doc_Commentsteht, dann wird dieses Leer zeichen nicht in die XML-Ausgabe aufgenommen.

In einem Delimited_Doc_Comment, wenn das erste Nicht-Leer -zeichen in der zweiten Zeile ein STERNCHEN ist und das gleiche Muster aus optionalen Leer -zeichen und einem STERNCHEN --Zeichen am Anfang jeder der Zeilen innerhalb des Delimited_Doc_Commentwiederholt wird, dann werden die Zeichen des wiederholten Musters nicht in die XML-Ausgabe aufgenommen. Das Muster kann Leer zeichen sowohl nach als auch vor dem STERNCHEN -Zeichen enthalten.

Beispiel:

/// <summary>
/// Class <c>Point</c> models a point in a two-dimensional plane.
/// </summary>
public class Point
{
    /// <summary>
    /// Method <c>Draw</c> renders the point.
    /// </summary>
    void Draw() {...}
}

Der Text in den Dokumentationskommentaren muss gemäß den Regeln von XML (http://www.w3.org/TR/REC-xml) wohlgeformt sein. Wenn das XML schlecht geformt ist, wird eine Warnung erzeugt und die Dokumentationsdatei enthält einen Kommentar, der besagt, dass ein Fehler aufgetreten ist.

Obwohl es den Entwicklern freisteht, ihre eigene Reihe von Tags zu erstellen, ist eine empfohlene Reihe in §D.3definiert. Einige der empfohlenen Tags haben eine besondere Bedeutung:

  • Das <param>-Tag wird verwendet, um Parameter zu beschreiben. Wenn ein solches Tag verwendet wird, muss der Dokumentationsgenerator überprüfen, ob der angegebene Parameter existiert und ob alle Parameter in Dokumentationskommentaren beschrieben sind. Wenn diese Überprüfung fehlschlägt, gibt der Dokumentationsgenerator eine Warnung aus.

  • Das cref-Attribut kann an jedes Tag angefügt werden, um einen Verweis auf ein Codeelement bereitzustellen. Der Dokumentationsgenerator muss überprüfen, ob dieses Codeelement existiert. Wenn die Überprüfung fehlschlägt, gibt der Dokumentationsgenerator eine Warnung aus. Bei der Suche nach einem Namen, der in einem cref -Attribut beschrieben ist, muss der Dokumentationsgenerator die Namespace-Sichtbarkeit gemäß den using-Anweisungen im Quellcode beachten. Für Code-Elemente, die generisch sind, kann die normale generische Syntax (z. B. „List<T>“) nicht verwendet werden, da sie ungültiges XML erzeugt. Anstelle von Klammern können auch geschweifte Klammern (z. B. „List{T}“) oder die XML-Escape-Syntax verwendet werden (z. B. „List&lt;T&gt;“).

  • Der <summary> -Tag ist dafür gedacht, dass ein Dokumentationsbetrachter zusätzliche Informationen über einen Typ oder ein Mitglied anzeigt.

  • Der Tag <include> enthält Informationen aus einer externen XML-Datei.

Beachten Sie sorgfältig, dass die Dokumentationsdatei keine vollständigen Informationen über den Typ und die Mitglieder enthält (z. B. enthält sie keine Typinformationen). Um solche Informationen über einen Typ oder ein Mitglied zu erhalten, muss die Dokumentationsdatei in Verbindung mit der Reflexion über den Typ oder das Mitglied verwendet werden.

Ein partieller Typ oder eine partielle Methode kann in mehreren Teilen deklariert werden, die jeweils in einer oder mehreren Kompiliereinheiten enthalten sein können und die jeweils einen oder mehrere Dokumentationskommentare enthalten können. Eine partielle Methode hat in der Regel eine „definierende partielle Erklärung“ und eine „implementierende partielle Erklärung“.

Für einen partiellen Typ werden die Dokumentenkommentare, die sich direkt auf diesen Typ beziehen, falls vorhanden, aus jedem seiner Teile in die Dokumentationsdatei geschrieben, und zwar in einer nicht festgelegten Reihenfolge.

Für eine partielle Methode:

  • Wenn eine definierende Teildeklaration keine entsprechende implementierende Teildeklaration hat, werden alle Dokumentationskommentare in dieser definierenden Teildeklaration ignoriert (da diese Deklaration entfernt wird).
  • Andernfalls, wenn die implementierende Teildeklaration Dokumentationskommentare enthält, werden diese in die Dokumentationsdatei geschrieben und alle Dokumentationskommentare in der definierenden Teildeklaration werden ignoriert.
  • Andernfalls werden alle Dokumentationskommentare in der definierenden Teildeklaration in die Dokumentationsdatei geschrieben.

D.3.1 Allgemeines

Der Dokumentationsgenerator muss jedes Tag akzeptieren und verarbeiten, das nach den Regeln von XML gültig ist. Die folgenden Tags stellen häufig verwendete Funktionen in der Benutzerdokumentation bereit. (Natürlich sind auch andere Tags möglich.)

Etikett Referenz Zweck
<c> §D.3.2 Text in eine codeähnliche Schriftart setzen
<code> §D.3.3 Eine oder mehrere Zeilen Quellcode oder Programmausgabe einstellen
<example> §D.3.4 Geben Sie ein Beispiel an
<exception> §D.3.5 Identifiziert die Ausnahmen, die eine Methode auslösen kann
<include> §D.3.6 Inkludiert XML aus einer externen Datei
<list> §D.3.7 Erstellen einer Liste oder Tabelle
<para> §D.3.8 Hinzufügen einer Struktur zum Text zulassen
<param> §D.3.9 Beschreiben eines Parameters für eine Methode oder einen Konstruktor
<paramref> §D.3.10 Erkennen, dass ein Wort ein Parametername ist
<permission> §D.3.11 Dokumentieren Sie die Sicherheitszugänglichkeit eines Mitglieds
<remarks> §D.3.12 Beschreiben zusätzlicher Informationen über einen Typ
<returns> §D.3.13 Beschreiben des Rückgabewerts einer Methode
<see> §D.3.14 Festlegen eines Links
<seealso> §D.3.15 Erzeugen Sie einen Siehe auch-Eintrag
<summary> §D.3.16 Beschreiben Sie einen Typ oder ein Mitglied eines Typs
<typeparam> §D.3.17 Beschreiben eines Typparameters für einen generischen Typ oder eine Methode
<typeparamref> §D.3.18 Erkennen, dass ein Wort ein Typ-Parametername ist
<value> §D.3.19 Beschreiben Sie eine Eigenschaft

D.3.2 <c>

Dieses Tag bietet einen Mechanismus, um anzugeben, dass ein Textfragment innerhalb einer Beschreibung in einer speziellen Schriftart, wie z. B. für einen Codeblock, gesetzt werden soll. Für Zeilen mit tatsächlichem Code verwenden Sie <code> (§D.3.3).

Syntax:

<c> Text</c>

Beispiel:

/// <summary>
/// Class <c>Point</c> models a point in a two-dimensional plane.
/// </summary>
public class Point
{
}

D.3.3-Kode <>

Dieses Tag wird verwendet, um eine oder mehrere Zeilen des Quellcodes oder der Programmausgabe in einer speziellen Schriftart auszugeben. Für kleine Codefragmente in Erzählungen verwenden Sie <c> (§D.3.2).

Syntax:

<code> Quellcode oder Programmausgabe</code>

Beispiel:

public class Point
{
    /// <summary>
    /// This method changes the point's location by the given x- and y-offsets.
    /// <example>
    /// For example:
    /// <code>
    /// Point p = new Point(3,5);
    /// p.Translate(-1,3);
    /// </code>
    /// results in <c>p</c>'s having the value (2,8).
    /// </example>
    /// </summary>
    public void Translate(int dx, int dy)
    {
        ...
    }
}

D.3.4 <Beispiel>

Mit diesem Tag können Sie in einem Kommentar Beispielcode angeben, wie eine Methode oder ein anderes Bibliotheksmitglied verwendet werden kann. Normalerweise würde dies auch die Verwendung des Tags <code> (§D.3.3) mit einschließen.

Syntax:

<example> Beschreibung</example>

Beispiel:

Siehe <code> (§D.3.3) für ein Beispiel.

D.3.5 <Ausnahme>

Dieses Tag bietet eine Möglichkeit, die Ausnahmen zu dokumentieren, die eine Methode auslösen kann.

Syntax:

<exception cref=" Mitglied">Beschreibung</exception>

Hierbei gilt:

  • cref=" member" ist der Name eines Mitglieds. Der Dokumentationsgenerator überprüft, ob das angegebene Mitglied existiert und übersetzt Mitglied in den kanonischen Elementnamen in der Dokumentationsdatei.
  • description ist eine Beschreibung der Umstände, unter denen die Ausnahme ausgelöst wird.

Beispiel:

class PrimaryFileFormatCorruptException : System.Exception { ... }
class PrimaryFileLockedOpenException : System.Exception { ... }

public class DataBaseOperations
{
    /// <exception cref="PrimaryFileFormatCorruptException">
    /// Thrown when the primary file is corrupted.
    /// </exception>
    /// <exception cref="PrimaryFileLockedOpenException">
    /// Thrown when the primary file is already open.
    /// </exception>
    public static void ReadRecord(int flag)
    {
        if (flag == 1)
        {
            throw new PrimaryFileFormatCorruptException();
        }
        else if (flag == 2)
        {
            throw new PrimaryFileLockedOpenException();
        }
        ...
    }
}

D.3.6 <einschließen>

Mit diesem Tag können Sie Informationen aus einem XML-Dokument einfügen, das sich außerhalb der Quellcodedatei befindet. Bei der externen Datei muss es sich um ein wohlgeformtes XML-Dokument handeln. Ein XPath-Ausdruck wird auf dieses Dokument angewendet, um anzugeben, welche XML-Daten aus diesem Dokument einbezogen werden sollen. Der <include> -Tag wird dann durch das ausgewählte XML aus dem externen Dokument ersetzt.

Syntax:

<include file=" Dateiname" path="XPath" />

Hierbei gilt:

  • file=" filename" ist der Dateiname einer externen XML-Datei. Der Dateiname wird relativ zu der Datei interpretiert, die das Include-Tag enthält.
  • path=" xpath" ist ein XPath-Ausdruck, der einen Teil des XML in der externen XML-Datei auswählt.

Beispiel:

Wenn der Quellcode eine Erklärung enthält wie:

/// <include file="docs.xml" path='extradoc/class[@name="IntList"]/*' />
public class IntList { ... }

und die externe Datei "docs.xml" hatte den folgenden Inhalt:

<?xml version="1.0"?>
<extradoc>
    <class name="IntList">
        <summary>
            Contains a list of integers.
        </summary>
    </class>
    <class name="StringList">
        <summary>
            Contains a list of strings.
        </summary>
    </class>
</extradoc>

dann wird die gleiche Dokumentation ausgegeben, als ob der Quellcode enthalten wäre:

/// <summary>
/// Contains a list of integers.
/// </summary>
public class IntList { ... }

Liste D.3.7 <>

Dieses Tag wird verwendet, um eine Liste oder Tabelle von Elementen zu erstellen. Sie kann einen <listheader> -Block enthalten, um die Überschriftenzeile einer Tabelle oder einer Definitionsliste zu definieren. (Bei der Definition einer Tabelle muss nur ein Eintrag für term in der Überschrift angegeben werden).

Jedes Element der Liste wird mit einem <item>-Block angegeben. Wenn Sie eine Definitionsliste erstellen, müssen sowohl term als auch description angegeben werden. Für eine Tabelle, Aufzählungsliste oder nummerierte Liste muss jedoch nur description angegeben werden.

Syntax:

<list type="bullet" | "number" | "table">
    <listheader>
        <term>term</term>
        <description>description</description>
    </listheader>
    <item>
        <term>term</term>
        <description>description</description>
    </item>
    ...
    <item>
        <term>term</term>
        <description>description</description>
    </item>
</list>

Hierbei gilt:

  • term ist der zu definierende Begriff, dessen Definition in Beschreibung steht.
  • description ist entweder ein Element in einer Aufzählung oder nummerierten Liste oder die Definition eines Begriffs.

Beispiel:

public class MyClass
{
    /// <summary>Here is an example of a bulleted list:
    /// <list type="bullet">
    /// <item>
    /// <description>Item 1.</description>
    /// </item>
    /// <item>
    /// <description>Item 2.</description>
    /// </item>
    /// </list>
    /// </summary>
    public static void Main()
    {
        ...
    }
}

D.3.8 <Absatz>

Dieses Tag ist für die Verwendung innerhalb anderer Tags gedacht, wie z. B. <summary> (§D.3.16) oder <returns> (§D.3.13), und ermöglicht das Hinzufügen einer Struktur zum Text.

Syntax:

<para> Inhalt</para>

Hierbei gilt:

  • content Inhalt ist der Text des Absatzes.

Beispiel:

public class Point
{
    /// <summary>This is the entry point of the Point class testing program.
    /// <para>
    /// This program tests each method and operator, and
    /// is intended to be run after any non-trivial maintenance has
    /// been performed on the Point class.
    /// </para>
    /// </summary>
    public static void Main() 
    {
        ...
    }
}

D.3.9 <Parameter>

Dieses Tag wird verwendet, um einen Parameter für eine Methode, einen Konstruktor oder einen Indexer zu beschreiben.

Syntax:

<param name=" Name">Beschreibung</param>

Hierbei gilt:

  • name ist der Name des Parameters.
  • description ist eine Beschreibung des Parameters.

Beispiel:

public class Point
{
    /// <summary>
    /// This method changes the point's location to
    /// the given coordinates.
    /// </summary>
    /// <param name="xPosition">the new x-coordinate.</param>
    /// <param name="yPosition">the new y-coordinate.</param>
    public void Move(int xPosition, int yPosition)
    {
        ...
    }
}

D.3.10 <paramref>

Dieses Tag wird verwendet, um anzuzeigen, dass ein Wort ein Parameter ist. Die Dokumentationsdatei kann bearbeitet werden, um diesen Parameter auf eine bestimmte Weise zu formatieren.

Syntax:

<paramref name=" Name"/>

Hierbei gilt:

  • name ist der Name des Parameters.

Beispiel:

public class Point
{
    /// <summary>This constructor initializes the new Point to
    /// (<paramref name="xPosition"/>,<paramref name="yPosition"/>).
    /// </summary>
    /// <param name="xPosition">the new Point's x-coordinate.</param>
    /// <param name="yPosition">the new Point's y-coordinate.</param>
    public Point(int xPosition, int yPosition)
    {
        ...
    }
}

D.3.11 <Erlaubnis>

Mit diesem Tag kann die Sicherheitszugänglichkeit eines Mitglieds dokumentiert werden.

Syntax:

<permission cref=" Mitglied">Beschreibung</permission>

Hierbei gilt:

  • member ist der Name eines Mitglieds. Der Dokumentationsgenerator prüft, ob das angegebene Codeelement existiert und übersetzt Mitglied in den kanonischen Elementnamen in der Dokumentationsdatei.
  • description ist eine Beschreibung des Zugriffs auf das Mitglied.

Beispiel:

public class MyClass
{
    /// <permission cref="System.Security.PermissionSet">
    /// Everyone can access this method.
    /// </permission>
    public static void Test()
    {
        ...
    }
}

D.3.12 <Bemerkungen>

Dieses Tag wird verwendet, um zusätzliche Informationen über einen Typ anzugeben. Verwenden Sie <summary> (§D.3.16), um den Typ selbst und die Mitglieder eines Typs zu beschreiben.

Syntax:

<remarks> Beschreibung</remarks>

Hierbei gilt:

  • description ist der Text der Bemerkung.

Beispiel:

/// <summary>
/// Class <c>Point</c> models a point in a two-dimensional plane.
/// </summary>
/// <remarks>
/// Uses polar coordinates
/// </remarks>
public class Point
{
    ...
}

D.3.13 <Rückgabe>

Dieses Tag wird verwendet, um den Rückgabewert einer Methode zu beschreiben.

Syntax:

<returns> Beschreibung</returns>

Hierbei gilt:

  • description ist eine Beschreibung des Rückgabewerts.

Beispiel:

public class Point
{
    /// <summary>
    /// Report a point's location as a string.
    /// </summary>
    /// <returns>
    /// A string representing a point's location, in the form (x,y),
    /// without any leading, trailing, or embedded whitespace.
    /// </returns>
    public override string ToString() => $"({X},{Y})";
    public int X { get; set; }
    public int Y { get; set; }
}

D.3.14 <siehe>

Mit diesem Tag kann ein Link im Text angegeben werden. Verwenden Sie <seealso> (§D.3.15), um Text zu kennzeichnen, der in einem See Also Nebensatz erscheinen soll.

Syntax:

<see cref=" Mitglied" href="URL (Englisch)" langword="Schlüsselwort" />

Hierbei gilt:

  • member ist der Name eines Mitglieds. Der Dokumentationsgenerator prüft, ob das angegebene Codeelement existiert und ändert Mitglied in der generierten Dokumentationsdatei in den Elementnamen um.
  • url ist ein Verweis auf eine externe Quelle.
  • langword ist ein Wort, das irgendwie hervorgehoben werden soll.

Beispiel:

public class Point
{
    /// <summary>
    /// This method changes the point's location to
    /// the given coordinates. <see cref="Translate"/>
    /// </summary>
    public void Move(int xPosition, int yPosition)
    {
        ...
    }
    /// <summary>This method changes the point's location by
    /// the given x- and y-offsets. <see cref="Move"/>
    /// </summary>
    public void Translate(int dx, int dy)
    {
        ...
    }
}

D.3.15 <siehe auch>

Mit diesem Tag kann ein Eintrag für die Subklausel See Also erzeugt werden. Verwenden Sie <see> (§D.3.14), um einen Link aus einem Text heraus anzugeben.

Syntax:

<seealso cref=" Mitglied" href="URL (Englisch)" />

Hierbei gilt:

  • member ist der Name eines Mitglieds. Der Dokumentationsgenerator prüft, ob das angegebene Codeelement existiert und ändert Mitglied in der generierten Dokumentationsdatei in den Elementnamen um.
  • url ist ein Verweis auf eine externe Quelle.

Beispiel:

public class Point
{
    /// <summary>
    /// This method determines whether two Points have the same location.
    /// </summary>
    /// <seealso cref="operator=="/>
    /// <seealso cref="operator!="/>
    public override bool Equals(object o)
    {
        ...
    }
}

D.3.16 <Zusammenfassung>

Dieses Tag kann verwendet werden, um einen Typ oder ein Element eines Typs zu beschreiben. Verwenden Sie <remarks> (§D.3.12), um zusätzliche Informationen über den Typ oder das Mitglied anzugeben.

Syntax:

<summary> Beschreibung</summary>

Hierbei gilt:

  • description ist eine Zusammenfassung des Typs oder Mitglieds.

Beispiel:

public class Point
{

    /// <summary>
    /// This constructor initializes the new Point to
    /// (<paramref name="xPosition"/>,<paramref name="yPosition"/>).
    /// </summary>
    public Point(int xPosition, int yPosition) 
    {
        ...
    }

    /// <summary>This constructor initializes the new Point to (0,0).</summary>
    public Point() : this(0, 0)
    {
    }
}

D.3.17 <typeparam>

Dieses Tag wird verwendet, um einen Typparameter für einen generischen Typ oder eine Methode zu beschreiben.

Syntax:

<typeparam name=" Name">Beschreibung</typeparam>

Hierbei gilt:

  • name ist der Name des Typparameters.
  • description ist eine Beschreibung des Typparameters.

Beispiel:

/// <summary>A generic list class.</summary>
/// <typeparam name="T">The type stored by the list.</typeparam>
public class MyList<T>
{
   ...
}

D.3.18 <typeparamref>

Dieses Tag wird verwendet, um anzuzeigen, dass ein Wort ein Typparameter ist. Die Dokumentationsdatei kann bearbeitet werden, um diesen Typ-Parameter in einer bestimmten Weise zu formatieren.

Syntax:

<typeparamref name=" Name"/>

Hierbei gilt:

  • name ist der Name des Typparameters.

Beispiel:

public class MyClass
{
    /// <summary>
    /// This method fetches data and returns a list of
    /// <typeparamref name="T"/>.
    /// </summary>
    /// <param name="query">query to execute</param>
    public List<T> FetchData<T>(string query)
    {
        ...
    }
}

D.3.19 <Wert>

Mit diesem Tag kann eine Eigenschaft beschrieben werden.

Syntax:

<value> Objektbeschreibung</value>

Hierbei gilt:

  • property description ist eine Beschreibung für die Eigenschaft.

Beispiel:

public class Point
{
    /// <value>Property <c>X</c> represents the point's x-coordinate.</value>
    public int X { get; set; }
}

D.4 Bearbeitung der Dokumentationsdatei

D.4.1 Allgemeines

Die folgenden Informationen sind für C#-Implementierungen gedacht, die auf die CLI abzielen.

Der Dokumentationsgenerator erzeugt eine ID-Zeichenfolge für jedes Element im Quellcode, das mit einem Dokumentationskommentar versehen ist. Diese ID-Zeichenfolge identifiziert ein Quellelement eindeutig. Ein Dokumentationsbetrachter kann eine ID-Zeichenfolge verwenden, um das entsprechende Objekt zu identifizieren, auf das sich die Dokumentation bezieht.

Bei der Dokumentationsdatei handelt es sich nicht um eine hierarchische Darstellung des Quellcodes, sondern um eine flache Liste mit einer generierten ID-Zeichenfolge für jedes Element.

D.4.2 Format der ID-Zeichenfolge

Der Dokumentationsgenerator beachtet die folgenden Regeln, wenn er die ID-Zeichenfolgen erzeugt:

  • In der Zeichenfolge wird kein Leerraum platziert.

  • Der erste Teil der Zeichenfolge identifiziert die Art des Mitglieds, das dokumentiert wird, durch ein einzelnes Zeichen gefolgt von einem Doppelpunkt. Die folgenden Arten von Mitgliedern sind definiert:

    Zeichen Beschreibung
    E Ereignis
    F Feld
    M Methode (einschließlich Konstruktoren, Finalizer und Operatoren)
    N Namespace
    P Eigenschaft (einschließlich Indexer)
    T Typ (wie Klasse, Delegat, Enumeration, Schnittstelle und Struktur)
    ! Fehlerstring; der Rest der Zeichenfolge enthält Informationen über den Fehler. Der Dokumentationsgenerator erzeugt zum Beispiel Fehlerinformationen für Links, die nicht aufgelöst werden können.
  • Der zweite Teil der Zeichenfolge ist der vollständig qualifizierte Name des Elements, beginnend mit der Wurzel des Namespaces. Der Name des Elements, seine umschließenden Typen und der Namensraum werden durch Punkte getrennt. Wenn der Name des Elements selbst Punkte enthält, werden diese durch das Zeichen # (U+0023) ersetzt. (Es wird davon ausgegangen, dass kein Element dieses Zeichen in seinem Namen hat.) Typargumente im vollqualifizierten Namen, wenn ein Element explizit ein Element einer generischen Schnittstelle implementiert, werden kodiert, indem die sie umgebenden „<“ und „>“ durch die Zeichen „{“ und „}“ ersetzt werden.

  • Bei Methoden und Eigenschaften mit Argumenten folgt die Argumentliste, eingeschlossen in Klammern. Für diejenigen, die keine Argumente haben, werden die Klammern weggelassen. Die Argumente werden durch Kommas voneinander getrennt. Die Kodierung jedes Arguments ist die gleiche wie bei einer CLI-Signatur, wie folgt:

    • Argumente werden durch ihren Dokumentationsnamen dargestellt, der auf ihrem vollqualifizierten Namen basiert und wie folgt geändert wird:
      • Argumente, die generische Typen darstellen, haben ein angehängtes „'“-Zeichen, gefolgt von der Anzahl der Typparameter
      • Argumente mit dem Modifikator in, out oder ref haben ein @ nach ihrem Typnamen. Argumente, die als Wert oder über params übergeben werden, haben keine besondere Notation.
      • Argumente, die Arrays sind, werden als [Untergrenze:Größe, dargestellt ... , lowerbound:size], wobei die Anzahl der Kommas der Rang abzüglich eins ist und die Untergrenzen und die Größe jeder Dimension, sofern bekannt, in Dezimalzahlen angegeben werden. Wenn keine Untergrenze oder Größe angegeben ist, wird sie weggelassen. Wenn die untere Schranke und die Größe für eine bestimmte Dimension weggelassen werden, wird auch das „:“ weggelassen. Jagged Arrays werden durch ein „[]“ pro Ebene dargestellt. Bei eindimensionalen Arrays wird die untere Grenze weggelassen, wenn die untere Grenze 0 ist (die Vorgabe) (§17.1).
      • Argumente, die andere Zeigertypen als void haben, werden mit einem * nach dem Typnamen dargestellt. Ein void -Zeiger wird mit einem Typnamen von System.Voiddargestellt.
      • Argumente, die sich auf generische Typparameter beziehen, die auf Typen definiert sind, werden mit dem Zeichen „`“ kodiert, gefolgt von dem nullbasierten Index des Typparameters.
      • Argumente, die generische Typparameter verwenden, die in Methoden definiert sind, verwenden ein Doppel-Backick „``“ anstelle des für Typen verwendeten „`“.
      • Argumente, die sich auf konstruierte generische Typen beziehen, werden mit dem generischen Typ kodiert, gefolgt von „{“, gefolgt von einer kommagetrennten Liste von Typargumenten, gefolgt von „}“.

D.4.3 Beispiele für ID-Zeichenfolgen

Die folgenden Beispiele zeigen jeweils ein Fragment von C#-Code zusammen mit der ID-Zeichenfolge, die von jedem Quellelement erzeugt wird, das einen Dokumentationskommentar enthalten kann:

Typen werden durch ihren voll qualifizierten Namen dargestellt, der durch generische Informationen ergänzt wird:

enum Color { Red, Blue, Green }

namespace Acme
{
    interface IProcess { ... }

    struct ValueType { ... }

    class Widget : IProcess
    {
        public class NestedClass { ... }
        public interface IMenuItem { ... }
        public delegate void Del(int i);
        public enum Direction { North, South, East, West }
    }

    class MyList<T>
    {
        class Helper<U,V> { ... }
    }
}

Ids:

"T:Color"
"T:Acme.IProcess"
"T:Acme.ValueType"
"T:Acme.Widget"
"T:Acme.Widget.NestedClass"
"T:Acme.Widget.IMenuItem"
"T:Acme.Widget.Del"
"T:Acme.Widget.Direction"
"T:Acme.MyList`1"
"T:Acme.MyList`1.Helper`2"

Felder werden durch ihren voll qualifizierten Namen dargestellt.

namespace Acme
{
    struct ValueType
    {
        private int total;
    }

    class Widget : IProcess
    {
        public class NestedClass
        {
            private int value;
        }

        private string message;
        private static Color defaultColor;
        private const double PI = 3.14159;
        protected readonly double monthlyAverage;
        private long[] array1;
        private Widget[,] array2;
        private unsafe int *pCount;
        private unsafe float **ppValues;
    }
}

Ids:

"F:Acme.ValueType.total"
"F:Acme.Widget.NestedClass.value"
"F:Acme.Widget.message"
"F:Acme.Widget.defaultColor"
"F:Acme.Widget.PI"
"F:Acme.Widget.monthlyAverage"
"F:Acme.Widget.array1"
"F:Acme.Widget.array2"
"F:Acme.Widget.pCount"
"F:Acme.Widget.ppValues"

Konstruktoren

namespace Acme
{
    class Widget : IProcess
    {
        static Widget() { ... }
        public Widget() { ... }
        public Widget(string s) { ... }
    }
}

Ids:

"M:Acme.Widget.#cctor"
"M:Acme.Widget.#ctor"
"M:Acme.Widget.#ctor(System.String)"

Finalizer

namespace Acme
{
    class Widget : IProcess
    {
        ~Widget() { ... }
    }
}

Ids:

"M:Acme.Widget.Finalize"

Methoden

namespace Acme
{
    struct ValueType
    {
        public void M(int i) { ... }
    }

    class Widget : IProcess
    {
        public class NestedClass
        {
            public void M(int i) { ... }
        }

        public static void M0() { ... }
        public void M1(char c, out float f, ref ValueType v, in int i) { ... }
        public void M2(short[] x1, int[,] x2, long[][] x3) { ... }
        public void M3(long[][] x3, Widget[][,,] x4) { ... }
        public unsafe void M4(char *pc, Color **pf) { ... }
        public unsafe void M5(void *pv, double *[][,] pd) { ... }
        public void M6(int i, params object[] args) { ... }
    }

    class MyList<T>
    {
        public void Test(T t) { ... }
    }

    class UseList
    {
        public void Process(MyList<int> list) { ... }
        public MyList<T> GetValues<T>(T value) { ... } 
    }
}

Ids:

"M:Acme.ValueType.M(System.Int32)"
"M:Acme.Widget.NestedClass.M(System.Int32)"
"M:Acme.Widget.M0"
"M:Acme.Widget.M1(System.Char,System.Single@,Acme.ValueType@,System.Int32@)"
"M:Acme.Widget.M2(System.Int16[],System.Int32[0:,0:],System.Int64[][])"
"M:Acme.Widget.M3(System.Int64[][],Acme.Widget[0:,0:,0:][])"
"M:Acme.Widget.M4(System.Char*,Color**)"
"M:Acme.Widget.M5(System.Void*,System.Double*[0:,0:][])"
"M:Acme.Widget.M6(System.Int32,System.Object[])"
"M:Acme.MyList`1.Test(`0)"
"M:Acme.UseList.Process(Acme.MyList{System.Int32})"
"M:Acme.UseList.GetValues``1(``0)"

Eigenschaften und Indexer

namespace Acme
{
    class Widget : IProcess
    {
        public int Width { get { ... } set { ... } }
        public int this[int i] { get { ... } set { ... } }
        public int this[string s, int i] { get { ... } set { ... } }
    }
}

Ids:

"P:Acme.Widget.Width"
"P:Acme.Widget.Item(System.Int32)"
"P:Acme.Widget.Item(System.String,System.Int32)"

Ereignisse

namespace Acme
{
    class Widget : IProcess
    {
        public event Del AnEvent;
    }
}

Ids:

"E:Acme.Widget.AnEvent"

Unäre Operatoren

namespace Acme
{
    class Widget : IProcess
    {
        public static Widget operator+(Widget x) { ... }
    }
}

Ids:

"M:Acme.Widget.op_UnaryPlus(Acme.Widget)"

Der vollständige Satz der verwendeten unären Operator-Funktionsnamen lautet wie folgt: op_UnaryPlus, op_UnaryNegation, op_LogicalNot, op_OnesComplement, op_Increment, op_Decrement, op_True und op_False.

Binäre Operatoren

namespace Acme
{
    class Widget : IProcess
    {
        public static Widget operator+(Widget x1, Widget x2) { ... }
    }
}

Ids:

"M:Acme.Widget.op_Addition(Acme.Widget,Acme.Widget)"

Der vollständige Satz der verwendeten biären Operator-Funktionsnamen lautet wie folgt: op_Addition, op_Subtraction, op_Multiply, op_Division, op_Modulus, op_BitwiseAnd, op_BitwiseOr, op_ExclusiveOr, op_LeftShift, op_RightShift, op_Equality, op_Inequality, op_LessThan, op_LessThanOrEqual, op_GreaterThan und op_GreaterThanOrEqual.

Konvertierungsoperatoren haben ein nachgestelltes „~“, gefolgt von dem Rückgabetyp. Wenn entweder die Quelle oder das Ziel eines Konvertierungsoperators ein generischer Typ ist, werden die Zeichen „<“ und „">“ durch die Zeichen „{“ bzw. „}“ ersetzt.

namespace Acme
{
    class Widget : IProcess
    {
        public static explicit operator int(Widget x) { ... }
        public static implicit operator long(Widget x) { ... }
    }
}

Ids:

"M:Acme.Widget.op_Explicit(Acme.Widget)~System.Int32"
"M:Acme.Widget.op_Implicit(Acme.Widget)~System.Int64"

D.5 Ein Beispiel

D.5.1 C#-Quellcode

Das folgende Beispiel zeigt den Quellcode einer Point-Klasse:

namespace Graphics
{
    /// <summary>
    /// Class <c>Point</c> models a point in a two-dimensional plane.
    /// </summary>
    public class Point
    {
        /// <value>
        /// Property <c>X</c> represents the point's x-coordinate.
        /// </value>
        public int X { get; set; }
        
        /// <value>
        /// Property <c>Y</c> represents the point's y-coordinate.
        /// </value>
        public int Y { get; set; }
        
        /// <summary>
        /// This constructor initializes the new Point to (0,0).
        /// </summary>
        public Point() : this(0, 0) {}
        
        /// <summary>
        /// This constructor initializes the new Point to
        /// (<paramref name="xPosition"/>,<paramref name="yPosition"/>).
        /// </summary>
        /// <param name="xPosition">The new Point's x-coordinate.</param>
        /// <param name="yPosition">The new Point's y-coordinate.</param>
        public Point(int xPosition, int yPosition) 
        {
            X = xPosition;
            Y = yPosition;
        }
        
        /// <summary>
        /// This method changes the point's location to
        /// the given coordinates. <see cref="Translate"/>
        /// </summary>
        /// <param name="xPosition">The new x-coordinate.</param>
        /// <param name="yPosition">The new y-coordinate.</param>
        public void Move(int xPosition, int yPosition) 
        {
            X = xPosition;
            Y = yPosition;
        }
        
        /// <summary>
        /// This method changes the point's location by
        /// the given x- and y-offsets.
        /// <example>For example:
        /// <code>
        /// Point p = new Point(3, 5);
        /// p.Translate(-1, 3);
        /// </code>
        /// results in <c>p</c>'s having the value (2, 8).
        /// <see cref="Move"/>
        /// </example>
        /// </summary>
        /// <param name="dx">The relative x-offset.</param>
        /// <param name="dy">The relative y-offset.</param>
        public void Translate(int dx, int dy)
        {
            X += dx;
            Y += dy;
        }
        
        /// <summary>
        /// This method determines whether two Points have the same location.
        /// </summary>
        /// <param name="o">
        /// The object to be compared to the current object.
        /// </param>
        /// <returns>
        /// True if the Points have the same location and they have
        /// the exact same type; otherwise, false.
        /// </returns>
        /// <seealso cref="operator=="/>
        /// <seealso cref="operator!="/>
        public override bool Equals(object o)
        {
            if (o == null)
            {
                return false;
            }
            if ((object)this == o) 
            {
                return true;
            }
            if (GetType() == o.GetType()) 
            {
                Point p = (Point)o;
                return (X == p.X) && (Y == p.Y);
            }
            return false;
        }

        /// <summary>
        /// This method returns a Point's hashcode.
        /// </summary>
        /// <returns>
        /// The int hashcode.
        /// </returns>
        public override int GetHashCode()
        {
            return X + (Y >> 4);    // a crude version
        }
        
        /// <summary>Report a point's location as a string.</summary>
        /// <returns>
        /// A string representing a point's location, in the form (x,y),
        /// without any leading, training, or embedded whitespace.
        /// </returns>
        public override string ToString() => $"({X},{Y})";
        
        /// <summary>
        /// This operator determines whether two Points have the same location.
        /// </summary>
        /// <param name="p1">The first Point to be compared.</param>
        /// <param name="p2">The second Point to be compared.</param>
        /// <returns>
        /// True if the Points have the same location and they have
        /// the exact same type; otherwise, false.
        /// </returns>
        /// <seealso cref="Equals"/>
        /// <seealso cref="operator!="/>
        public static bool operator==(Point p1, Point p2)
        {
            if ((object)p1 == null || (object)p2 == null)
            {
                return false;
            }
            if (p1.GetType() == p2.GetType())
            {
                return (p1.X == p2.X) && (p1.Y == p2.Y);
            }
            return false;
        }
        
        /// <summary>
        /// This operator determines whether two Points have the same location.
        /// </summary>
        /// <param name="p1">The first Point to be compared.</param>
        /// <param name="p2">The second Point to be compared.</param>
        /// <returns>
        /// True if the Points do not have the same location and the
        /// exact same type; otherwise, false.
        /// </returns>
        /// <seealso cref="Equals"/>
        /// <seealso cref="operator=="/>
        public static bool operator!=(Point p1, Point p2) => !(p1 == p2);
    }
}

D.5.2 Resultierende XML

Hier ist die Ausgabe, die ein Dokumentationsgenerator erzeugt, wenn er den oben gezeigten Quellcode für die Klasse Pointerhält:

<?xml version="1.0"?>
<doc>
  <assembly>
    <name>Point</name>
  </assembly>
  <members>
    <member name="T:Graphics.Point">
    <summary>Class <c>Point</c> models a point in a two-dimensional
    plane.
    </summary>
    </member>
    <member name="M:Graphics.Point.#ctor">
      <summary>This constructor initializes the new Point to (0, 0).</summary>
    </member>
    <member name="M:Graphics.Point.#ctor(System.Int32,System.Int32)">
      <summary>
        This constructor initializes the new Point to
        (<paramref name="xPosition"/>,<paramref name="yPosition"/>).
      </summary>
      <param name="xPosition">The new Point's x-coordinate.</param>
      <param name="yPosition">The new Point's y-coordinate.</param>
    </member>
    <member name="M:Graphics.Point.Move(System.Int32,System.Int32)">
      <summary>
        This method changes the point's location to
        the given coordinates.
        <see cref="M:Graphics.Point.Translate(System.Int32,System.Int32)"/>
      </summary>
      <param name="xPosition">The new x-coordinate.</param>
      <param name="yPosition">The new y-coordinate.</param>
      </member>
    <member name="M:Graphics.Point.Translate(System.Int32,System.Int32)">
      <summary>
        This method changes the point's location by
        the given x- and y-offsets.
        <example>For example:
        <code>
        Point p = new Point(3,5);
        p.Translate(-1,3);
        </code>
        results in <c>p</c>'s having the value (2,8).
        </example>
        <see cref="M:Graphics.Point.Move(System.Int32,System.Int32)"/>
      </summary>
      <param name="dx">The relative x-offset.</param>
      <param name="dy">The relative y-offset.</param>
    </member>
    <member name="M:Graphics.Point.Equals(System.Object)">
      <summary>
        This method determines whether two Points have the same location.
      </summary>
      <param name="o">
        The object to be compared to the current object.
      </param>
      <returns>
        True if the Points have the same location and they have
        the exact same type; otherwise, false.
      </returns>
      <seealso 
        cref="M:Graphics.Point.op_Equality(Graphics.Point,Graphics.Point)" />
      <seealso 
        cref="M:Graphics.Point.op_Inequality(Graphics.Point,Graphics.Point)"/>
    </member>
     <member name="M:Graphics.Point.ToString">
      <summary>
        Report a point's location as a string.
      </summary>
      <returns>
        A string representing a point's location, in the form (x,y),
        without any leading, training, or embedded whitespace.
      </returns>
     </member>
    <member name="M:Graphics.Point.op_Equality(Graphics.Point,Graphics.Point)">
      <summary>
        This operator determines whether two Points have the same location.
      </summary>
      <param name="p1">The first Point to be compared.</param>
      <param name="p2">The second Point to be compared.</param>
      <returns>
        True if the Points have the same location and they have
        the exact same type; otherwise, false.
      </returns>
      <seealso cref="M:Graphics.Point.Equals(System.Object)"/>
      <seealso
        cref="M:Graphics.Point.op_Inequality(Graphics.Point,Graphics.Point)"/>
    </member>
    <member
        name="M:Graphics.Point.op_Inequality(Graphics.Point,Graphics.Point)">
      <summary>
        This operator determines whether two Points have the same location.
      </summary>
      <param name="p1">The first Point to be compared.</param>
      <param name="p2">The second Point to be compared.</param>
      <returns>
        True if the Points do not have the same location and the
        exact same type; otherwise, false.
      </returns>
      <seealso cref="M:Graphics.Point.Equals(System.Object)"/>
      <seealso
        cref="M:Graphics.Point.op_Equality(Graphics.Point,Graphics.Point)"/>
      </member>
      <member name="M:Graphics.Point.Main">
        <summary>
          This is the entry point of the Point class testing program.
          <para>
            This program tests each method and operator, and
            is intended to be run after any non-trivial maintenance has
            been performed on the Point class.
          </para>
        </summary>
      </member>
      <member name="P:Graphics.Point.X">
        <value>
          Property <c>X</c> represents the point's x-coordinate.
        </value>
      </member>
      <member name="P:Graphics.Point.Y">
        <value>
          Property <c>Y</c> represents the point's y-coordinate.
        </value>
    </member>
  </members>
</doc>

Ende des informativen Textes.