Komentarze dokumentacji XML

Pliki źródłowe języka C# mogą mieć ustrukturyzowane komentarze, które tworzyć dokumentację interfejsu API dla typów zdefiniowanych w tych plikach. Kompilator języka C# tworzy plik XML , który zawiera ustrukturyzowane dane reprezentujące komentarze i podpisy interfejsu API. Inne narzędzia mogą przetwarzać dane wyjściowe XML w celu utworzenia dokumentacji czytelnej dla człowieka w formie stron internetowych lub plików PDF, na przykład.

Ten proces zapewnia wiele zalet dodawania dokumentacji interfejsu API w kodzie:

  • Kompilator języka C# łączy strukturę kodu C# z tekstem komentarzy w jednym dokumencie XML.
  • Kompilator języka C# sprawdza, czy komentarze są zgodne z podpisami interfejsu API dla odpowiednich tagów.
  • Narzędzia, które przetwarzają pliki dokumentacji XML, mogą definiować elementy XML i atrybuty specyficzne dla tych narzędzi.

Narzędzia takie Visual Studio zapewniają intelliSense dla wielu typowych elementów XML używanych w komentarzach do dokumentacji.

Ten artykuł obejmuje następujące tematy:

  • Komentarze dokumentacji i generowanie plików XML
  • Tagi zweryfikowane przez kompilator języka C# i Visual Studio
  • Format wygenerowanego pliku XML

Tworzenie danych wyjściowych dokumentacji XML

Aby utworzyć dokumentację dla kodu, należy napisać specjalne pola komentarzy wskazywane przez potrójne ukośniki. Pola komentarza zawierają elementy XML, które opisują blok kodu, który następuje po komentarzach. Na przykład:

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

Należy ustawić opcję GenerateDocumentationFile lub DocumentationFile , a kompilator znajdzie wszystkie pola komentarzy z tagami XML w kodzie źródłowym i utworzy plik dokumentacji XML na podstawie tych komentarzy. Gdy ta opcja jest włączona, kompilator generuje ostrzeżenie CS1591 dla każdego publicznie widocznego elementu członkowskiego zadeklarowanych w projekcie bez komentarzy dokumentacji XML.

Formaty komentarzy XML

Korzystanie z komentarzy dokumentacji XML wymaga ograniczników, które wskazują, gdzie zaczyna się i kończy komentarz do dokumentacji. Użyj następujących ograniczników z tagami dokumentacji XML:

  • /// Ogranicznik jedno wierszowy: przykłady dokumentacji i szablony projektów języka C# używają tego formularza. Jeśli po ograniczniku znajduje się biały znak, nie jest on uwzględniony w danych wyjściowych XML.

    Uwaga

    Visual Studio automatycznie wstawia tagi <summary> i </summary> i umieszcza kursor w tych tagach po wpisaniu /// ogranicznika w edytorze kodu. Tę funkcję można włączyć lub wyłączyć w oknie dialogowym Opcje.

  • /** */ Ograniczniki wieloliniowe: ograniczniki /** */ mają następujące reguły formatowania:
    • W wierszu zawierającym ogranicznik /** , jeśli pozostała część wiersza jest odstępem, wiersz nie jest przetwarzany na komentarze. Jeśli pierwszy znak po ograniczniku /** jest odstępem, ten znak odstępu jest ignorowany, a pozostała część wiersza jest przetwarzana. W przeciwnym razie cały tekst wiersza po ograniczniku /** jest przetwarzany jako część komentarza.

    • W wierszu, który zawiera ogranicznik */ , */ jeśli do ogranicznika znajduje się tylko biały znak odstępu, ten wiersz jest ignorowany. W przeciwnym razie tekst w wierszu do ogranicznika */ jest przetwarzany jako część komentarza.

    • W przypadku wierszy po wierszu rozpoczynającym się od ogranicznika /** kompilator szuka wspólnego wzorca na początku każdego wiersza. Wzorzec może składać się z opcjonalnego odstępu i gwiazdki (*), po której następuje więcej opcjonalnego odstępu. Jeśli kompilator znajdzie wspólny wzorzec /***/ na początku każdego wiersza, który nie zaczyna się od ogranicznika lub kończy się ogranicznikiem, ignoruje ten wzorzec dla każdego wiersza.

    • Jedyną częścią przetwarzanego komentarza jest wiersz, który zaczyna się od <summary>. Te trzy formaty tagów dają te same komentarze.

      /** <summary>text</summary> */
      
      /**
      <summary>text</summary>
      */
      
      /**
      * <summary>text</summary>
      */
      
    • Kompilator identyfikuje wspólny wzorzec " * " na początku drugiego i trzeciego wiersza. Wzorzec nie jest uwzględniony w danych wyjściowych.

      /**
      * <summary>
      * text </summary>*/
      
    • Kompilator nie znajduje wspólnego wzorca w poniższym komentarzu, ponieważ drugi znak w trzecim wierszu nie jest gwiazdką. Cały tekst w drugim i trzecim wierszach jest przetwarzany jako część komentarza.

      /**
      * <summary>
         text </summary>
      */
      
    • Kompilator nie znajduje wzorca w poniższym komentarzu z dwóch powodów. Po pierwsze, liczba spacji przed gwiazdką nie jest spójna. Po drugie piąty wiersz rozpoczyna się od karty, która nie pasuje do spacji. Cały tekst z wierszy od dwóch do pięciu jest przetwarzany jako część komentarza.

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

Aby odwołać się do elementów XML (na przykład funkcja przetwarza określone elementy XML, które chcesz opisać w komentarzu do dokumentacji XML), możesz użyć standardowego mechanizmu cudzysłowego (&lt; i &gt;). Aby odwołać się do identyfikatorów ogólnych w elementach odwołania do kodu (cref), można użyć znaków ucieczki ( cref="List&lt;T&gt;"na przykład ) lub nawiasów klamrowych (cref="List{T}"). Jest to szczególny przypadek, w którym kompilator analizuje nawiasy klamrowe jako nawiasy kątowe, dzięki czemu komentarz dokumentacji jest wygodniejszy dla autora, gdy ten odwołuje się do identyfikatorów ogólnych.

Uwaga

Komentarze dokumentacji XML nie są metadanymi; nie są one uwzględniane w kompilowanym zestawie i dlatego są niedostępne za pośrednictwem mechanizmu odbicia.

Narzędzia akceptujące dane wejściowe dokumentacji XML

Następujące narzędzia tworzą dane wyjściowe z komentarzy XML:

  • DocFX: DocFX to generator dokumentacji interfejsu API dla platformy .NET, który obecnie obsługuje język C#, Visual Basic i F#. Umożliwia również dostosowanie wygenerowanej dokumentacji referencyjnej. DocFX tworzy statyczną witrynę internetową HTML z kodu źródłowego i plików Markdown. Ponadto docFX zapewnia elastyczność dostosowywania układu i stylu witryny internetowej za pomocą szablonów. Można również tworzyć szablony niestandardowe.
  • Sand nie tylko: narzędzia Sand tworzyć pliki pomocy dla zarządzanych bibliotek klas zawierających strony referencyjne zarówno koncepcyjne, jak i interfejsu API. Narzędzia Sand z kolei są oparte na wierszu polecenia i nie mają frontonia z graficznym interfejsem użytkownika, funkcji zarządzania projektami ani zautomatyzowanego procesu kompilacji. Kreator plików pomocy Sand za pomocą autonomicznego graficznego interfejsu użytkownika i narzędzi wiersza polecenia umożliwia automatyczne tworzenie pliku pomocy. Dostępny Visual Studio integracyjny, dzięki czemu można tworzyć projekty pomocy i zarządzać nimi w całości z poziomu Visual Studio.
  • Doxygen: program Doxygen generuje przeglądarkę dokumentacji online (w języku HTML) lub podręcznik informacyjny offline (w języku LaTeX) z zestawu udokumentowanych plików źródłowych. Istnieje również obsługa generowania danych wyjściowych na stronach RTF (MS Word), PostScript PDF z hiperlinkami, skompresowanym kodem HTML, docBook i stronami man systemu Unix. Możesz skonfigurować program Doxygen do wyodrębniania struktury kodu z nieudokumentowanych plików źródłowych.

Ciągi identyfikatorów

Każdy typ lub element członkowski jest przechowywany w elemencie w wyjściowym pliku XML. Każdy z tych elementów ma unikatowy ciąg identyfikatora, który identyfikuje typ lub element członkowski. Ciąg identyfikatora musi uwzględniać operatory, parametry, wartości zwracane, parametry typu ogólnego, ref, ini out parametry. Aby zakodować wszystkie te potencjalne elementy, kompilator stosuje jasno zdefiniowane reguły generowania ciągów identyfikatorów. Programy, które przetwarzają plik XML, używają ciągu identyfikatora do identyfikowania odpowiednich metadanych .NET lub elementu odbicia, których dotyczy dokumentacja.

Podczas generowania ciągów identyfikatorów kompilator przestrzega następujących reguł:

  • W ciągu nie ma białych znaków.

  • Pierwsza część ciągu identyfikuje rodzaj składowej przy użyciu pojedynczego znaku, po którym następuje dwukropek. Używane są następujące typy elementów członkowskich:

    Znak Typ członka Uwagi
    N namespace Nie można dodawać komentarzy do dokumentacji do przestrzeni nazw, ale można odwołań do nich skojarzeń, jeśli jest to obsługiwane.
    T typ Typ to klasa, interfejs, struktura, wyliczanie lub delegat.
    F pole
    P property Zawiera indeksatory lub inne właściwości indeksowane.
    M method Obejmuje metody specjalne, takie jak konstruktory i operatory.
    E event
    ! ciąg błędu Pozostała część ciągu zawiera informacje o błędzie. Kompilator języka C# generuje informacje o błędzie dla linków, których nie można rozpoznać.
  • Druga część ciągu to w pełni kwalifikowana nazwa elementu, zaczynając od katalogu głównego przestrzeni nazw. Nazwy elementu, jego otaczające typy i przestrzeń nazw są oddzielone kropkami. Jeśli nazwa samego elementu ma kropki, są one zastępowane znakiem skrótu ("#"). Zakłada się, że żaden element nie ma znaku skrótu bezpośrednio w nazwie. Na przykład w pełni kwalifikowana nazwa konstruktora String to "System.String.#ctor".

  • W przypadku właściwości i metod lista parametrów ujęta w nawiasy jest następująca. Jeśli nie ma żadnych parametrów, nawiasy nie są obecne. Parametry są rozdzielane przecinkami. Kodowanie każdego parametru bezpośrednio następuje w sposób zakodowany w sygnaturze .NET ( Microsoft.VisualStudio.CorDebugInterop.CorElementType zobacz definicje wszystkich elementów z limitami na poniższej liście):

    • Typy podstawowe. Typy regularne (ELEMENT_TYPE_CLASS lub ELEMENT_TYPE_VALUETYPE) są reprezentowane jako w pełni kwalifikowana nazwa typu.
    • Typy wewnętrzne (na przykład ELEMENT_TYPE_I4, ELEMENT_TYPE_OBJECT, ELEMENT_TYPE_STRING, ELEMENT_TYPE_TYPEDBYREFi ELEMENT_TYPE_VOID) są reprezentowane jako w pełni kwalifikowana nazwa odpowiedniego pełnego typu. Na przykład: System.Int32 lub System.TypedReference.
    • ELEMENT_TYPE_PTR jest reprezentowany jako "*" po zmodyfikowanym typie.
    • ELEMENT_TYPE_BYREF jest reprezentowany jako "@" po zmodyfikowanym typie.
    • ELEMENT_TYPE_CMOD_OPT jest reprezentowany jako "!", a w pełni kwalifikowana nazwa klasy modyfikatora jest następująca po zmodyfikowanym typie.
    • ELEMENT_TYPE_SZARRAY jest reprezentowany jako "[]" po typie elementu tablicy.
    • ELEMENT_TYPE_ARRAY jest reprezentowany jako [ELEMENT_TYPE_ARRAY:size,size:size], gdzie liczba przecinków to ranga - 1, a dolne granice i rozmiar każdego wymiaru, jeśli są znane, są reprezentowane w postaci dziesiętnej. Jeśli dolna granica lub rozmiar nie zostanie określony, zostanie pominięty. Jeśli dolna granica i rozmiar dla określonego wymiaru zostaną pominięte, zostanie również pominięty ":". Na przykład tablica dwuwymiarowa z 1 jako dolną granicą i nieokreślonym rozmiarem to [1:,1:].
  • Tylko w przypadku operatorów konwersji (op_Implicit i op_Explicit) wartość zwracana metody jest kodowana jako typ ~ zwracany. Na przykład: <member name="M:System.Decimal.op_Explicit(System.Decimal arg)~System.Int32"> to tag operatora rzutowania zadeklarowany public static explicit operator int (decimal value); w System.Decimal klasie .

  • W przypadku typów ogólnych po nazwie typu następuje backtick, a następnie liczba wskazująca liczbę parametrów typu ogólnego. Na przykład: <member name="T:SampleClass``2"> to tag typu, który jest zdefiniowany jako public class SampleClass<T, U>. W przypadku metod, które jako parametry przyjmą typy ogólne, parametry typu ogólnego są określane jako liczby poprzedzone za pomocą oznaczania (na przykład "0", "1"). Każda liczba reprezentuje notację tablicy od zera dla parametrów ogólnych typu.

    • ELEMENT_TYPE_PINNED jest reprezentowany jako "^" po zmodyfikowanym typie. Kompilator języka C# nigdy nie generuje tego kodowania.
    • ELEMENT_TYPE_CMOD_REQ jest reprezentowany jako "|" i w pełni kwalifikowaną nazwę klasy modyfikatora, po zmodyfikowanym typie. Kompilator języka C# nigdy nie generuje tego kodowania.
    • ELEMENT_TYPE_GENERICARRAY jest reprezentowany jako "[?]" po typie elementu tablicy. Kompilator języka C# nigdy nie generuje tego kodowania.
    • ELEMENT_TYPE_FNPTR jest reprezentowany jako "=FUNC:type(ELEMENT_TYPE_FNPTR)", gdzie type jest zwracanym typem, a type jest argumentami metody . Jeśli nie ma argumentów, nawiasy zostaną pominięte. Kompilator języka C# nigdy nie generuje tego kodowania.
    • Następujące składniki sygnatur nie są reprezentowane, ponieważ nie są używane do rozróżniania metod przeciążonych:
      • konwencja wywoływania
      • typ zwracany
      • ELEMENT_TYPE_SENTINEL

W poniższych przykładach podano sposób generowania ciągów identyfikatorów dla klasy i jej składowych:

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

specyfikacja języka C#

Aby uzyskać więcej informacji, zobacz załącznik specyfikacji języka C# w komentarzach do dokumentacji.