Udostępnij za pomocą


Generowanie komentarzy dokumentacji interfejsu API XML

Pliki źródłowe języka C# mogą zawierać komentarze ustrukturyzowane, które tworzą dokumentację interfejsu API dla typów zdefiniowanych w tych plikach. Kompilator języka C# tworzy plik XML zawierający dane ustrukturyzowane reprezentujące komentarze i podpisy interfejsu API. Inne narzędzia mogą przetwarzać te dane wyjściowe XML w celu utworzenia dokumentacji czytelnej dla człowieka w postaci 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 pojedynczy dokument XML.
  • Kompilator języka C# sprawdza, czy komentarze są zgodne z sygnaturami 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 jak Visual Studio zapewniają funkcję IntelliSense dla wielu typowych elementów XML używanych w komentarzach dokumentacji.

W tym artykule opisano następujące tematy:

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

Tworzenie danych wyjściowych dokumentacji XML

Możesz utworzyć dokumentację dla kodu, pisząc specjalne pola komentarzy wskazywane przez potrójne ukośniki. Pola komentarza zawierają elementy XML opisujące blok kodu, który jest zgodny z komentarzami. Przykład:

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

Ustawiono opcję GenerateDocumentationFile lub DocumentationFile , a kompilator wyszukuje wszystkie pola komentarzy z tagami XML w kodzie źródłowym i tworzy plik dokumentacji XML z tych komentarzy. Po włączeniu tej opcji kompilator generuje ostrzeżenie CS1591 dla każdego publicznie widocznego elementu członkowskiego zadeklarowanego w projekcie bez komentarzy dokumentacji XML.

Formaty komentarzy XML

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

  • /// Ogranicznik jednowierszowy: przykłady dokumentacji i szablony projektów języka C# używają tego formularza. Jeśli odstęp jest zgodny z ogranicznikiem, nie jest uwzględniony w danych wyjściowych XML.

    Uwaga / Notatka

    Program Visual Studio automatycznie wstawia <summary> tagi i i </summary> 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 wielowierszowe: /** */ Ograniczniki mają następujące reguły formatowania:
    • W wierszu zawierającym /** ogranicznik, jeśli pozostała część wiersza jest białym znakiem, wiersz nie jest przetwarzany dla komentarzy. Jeśli pierwszy znak po ograniczniku /** jest białym znakiem, znak biały jest ignorowany, a reszta wiersza jest przetwarzana. W przeciwnym razie cały tekst wiersza po przetworzeniu /** ogranicznika w ramach komentarza.

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

    • W przypadku wierszy po tym, który zaczyna 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/lub gwiazdki (*), a następnie więcej opcjonalnego odstępu. Jeśli kompilator znajdzie typowy 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ą następującego przetworzonego komentarza jest wiersz rozpoczynający się od <summary>. Trzy formaty tagów tworzą 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 w ramach komentarza.

      /**
      * <summary>
         text </summary>
      */
      
    • Kompilator nie znajduje wzorca w następującym komentarzu z dwóch powodów. Po pierwsze, liczba spacji przed gwiazdką nie jest spójna. Po drugie piąty wiersz zaczyna się od karty, która nie pasuje do spacji. Cały tekst z wierszy od dwóch do pięciu jest przetwarzany w ramach 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 dokumentacji XML), możesz użyć standardowego mechanizmu cudzysłów (&lt; i &gt;). Aby odwołać się do identyfikatorów ogólnych w elementach odwołania do kodu (cref), możesz użyć znaków ucieczki (na przykład cref="List&lt;T&gt;") lub nawiasów klamrowych (cref="List{T}"). W specjalnym przypadku kompilator analizuje nawiasy klamrowe jako nawiasy kątowe, aby komentarz dokumentacji był mniej uciążliwy dla autora podczas odwoływania się do identyfikatorów ogólnych.

Uwaga / Notatka

Jeśli piszesz komentarze przy użyciu ogranicznika komentarza XML z jednym wierszem, ///, ale nie dołączasz żadnych tagów, kompilator dodaje tekst tych komentarzy do pliku wyjściowego XML. Jednak dane wyjściowe nie zawierają elementów XML, takich jak <summary>. Większość narzędzi korzystających z komentarzy XML (w tym funkcji IntelliSense programu Visual Studio) nie czyta tych komentarzy.

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ęzyki 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 rozwiązanie DocFX zapewnia elastyczność dostosowywania układu i stylu witryny internetowej za pomocą szablonów. Można również tworzyć szablony niestandardowe.
  • Sandcastle: narzędzia Sandcastle tworzą pliki pomocy dla zarządzanych bibliotek klas zawierających zarówno strony referencyjne pojęć, jak i interfejsu API. Narzędzia Sandcastle są oparte na wierszu polecenia i nie mają frontonu graficznego interfejsu użytkownika, funkcji zarządzania projektami ani zautomatyzowanego procesu kompilacji. Narzędzie Sandcastle Help File Builder udostępnia autonomiczny graficzny interfejs użytkownika i narzędzia oparte na wierszach polecenia do tworzenia pliku pomocy w zautomatyzowany sposób. Dostępny jest również pakiet integracji programu Visual Studio, dzięki czemu projekty pomocy można tworzyć i zarządzać w całości z poziomu programu Visual Studio.
  • Doxygen: Doxygen generuje przeglądarkę dokumentacji online (w języku HTML) lub podręcznik odwołania offline (w LaTeX) z zestawu udokumentowanych plików źródłowych. Istnieje również obsługa generowania danych wyjściowych w plikach RTF (MS Word), PostScript, hiperlinkowanych plikach PDF, skompresowanych plikach HTML, DocBook i Unix. Możesz skonfigurować narzędzie Doxygen, aby wyodrębnić strukturę kodu z nieudokumentowanych plików źródłowych.

Uwaga / Notatka

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

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 identyfikujący typ lub element członkowski. Ciąg identyfikatora musi uwzględniać operatory, parametry, wartości zwracane, parametry typu ogólnego, ref, ini out parametrów. Aby zakodować wszystkie te potencjalne elementy, kompilator jest zgodny z jasno zdefiniowanymi regułami generowania ciągów identyfikatorów. Programy, które przetwarzają plik XML, używają ciągu identyfikatora, aby zidentyfikować odpowiednie metadane platformy .NET lub element odbicia, do którego ma zastosowanie dokumentacja.

Kompilator obserwuje następujące reguły podczas generowania ciągów identyfikatorów:

  • W ciągu nie ma odstępu.

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

    Charakter Typ członkostwa Notatki
    N obszar nazw Nie można dodawać komentarzy dokumentacji do przestrzeni nazw, ale możesz do nich odwoływać cref się, gdzie jest obsługiwana.
    T typ Typ to klasa, interfejs, struktura, wyliczenie lub delegat.
    F pole
    P właściwość Zawiera indeksatory lub inne właściwości indeksowane.
    M metoda Zawiera specjalne metody, takie jak konstruktory i operatory.
    E wydarzenie
    ! 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 jest w pełni kwalifikowaną nazwą elementu, zaczynając od katalogu głównego przestrzeni nazw. Nazwa elementu, jego otaczające typy i przestrzeń nazw są oddzielone kropkami. Jeśli nazwa samego elementu zawiera kropki, są one zastępowane znakiem skrótu ('#'). Gramatyka zakłada, ż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 następuje. Jeśli nie ma żadnych parametrów, nie ma nawiasów. Parametry są rozdzielane przecinkami. Kodowanie każdego parametru jest zgodne bezpośrednio z kodowaniem w podpisie platformy .NET (zobacz Microsoft.VisualStudio.CorDebugInterop.CorElementType definicje wszystkich elementów limitów 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_OBJECTELEMENT_TYPE_STRING, ELEMENT_TYPE_TYPEDBYREFi ELEMENT_TYPE_VOID) są reprezentowane jako w pełni kwalifikowana nazwa odpowiadającego mu pełnego typu. Na przykład: System.Int32 lub System.TypedReference.
    • ELEMENT_TYPE_PTR element jest reprezentowany jako "*" po zmodyfikowanym typie.
    • ELEMENT_TYPE_BYREF element jest reprezentowany jako znak "@" po zmodyfikowanym typie.
    • ELEMENT_TYPE_CMOD_OPT element jest reprezentowany jako "!", a w pełni kwalifikowana nazwa klasy modyfikatora, po zmodyfikowanym typie.
    • ELEMENT_TYPE_SZARRAY element jest reprezentowany jako "[]" po typie elementu tablicy.
    • ELEMENT_TYPE_ARRAY jest reprezentowana jako [dolna granica:size,dolna granica:size], gdzie liczba przecinków to ranga - 1, a dolne granice i rozmiar każdego wymiaru, jeśli jest znany, są reprezentowane w przecinku. Dolna granica i rozmiar zostaną pominięte, jeśli nie zostaną określone. Jeśli pominięto dolną granicę i rozmiar dla określonego wymiaru, pominięto również wartość ":". Na przykład tablica dwuwymiarowa o wartości 1 jako dolna granica i nieokreślone rozmiary to [1:,1:].
  • Tylko dla operatorów konwersji (op_Implicit i op_Explicit) wartość zwracana metody jest zakodowana jako ~ po nim typ zwracany. Na przykład: <member name="M:System.Decimal.op_Explicit(System.Decimal arg)~System.Int32"> to tag operatora public static explicit operator int (decimal value); rzutowania zadeklarowany System.Decimal w klasie .

  • W przypadku typów ogólnych nazwa 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 zdefiniowanego jako public class SampleClass<T, U>. W przypadku metod, które przyjmują typy ogólne jako parametry, parametry typu ogólnego są określane jako liczby poprzedzone backticks (na przykład "0,"1). Każda liczba reprezentuje notację tablicy opartą na zerach dla parametrów ogólnych typu.

    • ELEMENT_TYPE_PINNED element jest reprezentowany jako '^' po zmodyfikowanym typie. Kompilator języka C# nigdy nie generuje tego kodowania.
    • ELEMENT_TYPE_CMOD_REQ jest reprezentowana jako '|' i w pełni kwalifikowana nazwa klasy modyfikatora, zgodnie z zmodyfikowanym typem. Kompilator języka C# nigdy nie generuje tego kodowania.
    • ELEMENT_TYPE_GENERICARRAY element jest reprezentowany jako "[?]" po typie elementu tablicy. Kompilator języka C# nigdy nie generuje tego kodowania.
    • ELEMENT_TYPE_FNPTRelement jest reprezentowany jako "=FUNC:(typesignature)", gdzie type jest typem zwrotnym, a podpis 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 podpisu nie są reprezentowane, ponieważ nie są używane do rozróżniania metod przeciążonych:
      • konwencja wywoływania
      • zwracany typ
      • ELEMENT_TYPE_SENTINEL

W poniższych przykładach pokazano, jak są generowane ciągi identyfikatorów 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() => 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 num, 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] => 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) => 1;
}

Specyfikacja języka C#

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