Поделиться через


Создание комментариев документации по XML API

Исходные файлы C# могут содержать структурированные комментарии, которые создают документацию ПО API для типов, определенных в этих файлах. Компилятор C# создает XML-файл , содержащий структурированные данные, представляющие комментарии и подписи API. Другие средства могут обрабатывать выходные данные XML для создания документации, доступной для чтения человеком, в виде веб-страниц или PDF-файлов, например.

Справочные документы на языке C#, выпущенные последней версией языка C#. Она также содержит начальную документацию по функциям в общедоступных предварительных версиях для предстоящего языкового выпуска.

Документация определяет любую функцию, впервые представленную в последних трех версиях языка или в текущих общедоступных предварительных версиях.

Подсказка

Чтобы узнать, когда функция впервые появилась в C#, ознакомьтесь со статьей по журналу версий языка C#.

Этот процесс предоставляет множество преимуществ для добавления документации ПО API в код:

  • Компилятор C# объединяет структуру кода C# с текстом комментариев в один XML-документ.
  • Компилятор C# проверяет, соответствуют ли комментарии подписям API для соответствующих тегов.
  • Средства, обрабатывающие XML-файлы документации, могут определять XML-элементы и атрибуты, относящиеся к этим средствам.

Такие инструменты, как Visual Studio, предоставляют IntelliSense для многих распространенных XML-элементов, используемых в комментариях документации.

В этой статье рассматриваются следующие разделы:

  • Комментарии к документации и создание XML-файла
  • Теги, проверенные компилятором C# и Visual Studio
  • Формат созданного XML-файла

Создание выходных данных XML-документации

Вы создаете документацию для кода, написав специальные поля комментариев, обозначаемые тройной косой чертой. Поля комментариев включают XML-элементы, описывающие блок кода, который следует комментариям. Рассмотрим пример.

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

Вы задаете параметр GenerateDocumentationFile или DocumentationFile . Компилятор находит все поля комментариев с XML-тегами в исходном коде и создает XML-файл документации из этих комментариев. При включении этого параметра компилятор создает предупреждение CS1591 для любого открыто видимого члена, объявленного в проекте без комментариев xml-документации.

Форматы комментариев XML

При использовании комментариев к XML-документам требуются разделители, указывающие, где начинается и заканчивается комментарий документации. Используйте следующие разделители с тегами XML-документации:

  • /// Однострочный разделитель: примеры документации и шаблоны проектов C# используют эту форму. Если пробел следует за разделителем, он не включается в выходные данные XML.

    Примечание.

    Visual Studio автоматически вставляет теги <summary> и </summary> и перемещает курсор в эти теги после того, как вы вводите разделитель /// в редакторе кода. Эту функцию можно включить или отключить в диалоговом окне "Параметры".

  • /** */ Многостроковые разделители: /** */ разделители имеют следующие правила форматирования:
    • В строке, содержащей /** разделитель, если остальная часть строки является пробелом, строка не обрабатывается для комментариев. Если первый символ после /** разделителя является пробелом, этот символ пробела игнорируется, а остальная часть строки обрабатывается. В противном случае весь текст строки после /** обрабатывается как часть комментария.

    • В строке, содержащей */ разделитель, если до */ разделителя есть только пробелы, эта строка игнорируется. В противном случае текст строки до */ разделителя обрабатывается как часть комментария.

    • Для строк после строки, начинающейся с /** разделителя, компилятор ищет общий шаблон в начале каждой строки. Шаблон может состоять из необязательных пробелов и (или) звездочки (*), за которыми следуют дополнительные пробелы. Если компилятор находит общий шаблон в начале каждой строки, которая не начинается с разделителя /** или не заканчивается разделителем */, он игнорирует этот шаблон для каждой строки.

    • Единственной частью следующего комментария, которая обрабатывается, является строка, начинающаяся с <summary>. Три формата тегов создают одни и те же комментарии.

      /** <summary>text</summary> */
      
      /**
      <summary>text</summary>
      */
      
      /**
      * <summary>text</summary>
      */
      
    • Компилятор определяет общий шаблон "* " в начале второй и третьей строк. Шаблон не включен в выходные данные.

      /**
      * <summary>
      * text </summary>*/
      
    • Компилятор не находит общий шаблон в следующем комментарии, так как второй символ на третьей строке не является звездочкой. Весь текст во второй и третьей строках обрабатывается как часть комментария.

      /**
      * <summary>
         text </summary>
      */
      
    • Компилятор не находит шаблон в следующем комментарии по двум причинам. Во-первых, количество пробелов перед звездочкой не согласовано. Во-вторых, пятая строка начинается с вкладки, которая не соответствует пробелам. Весь текст из строк два–пять обрабатывается как часть комментария.

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

Чтобы ссылаться на XML-элементы (например, функция обрабатывает определенные XML-элементы, которые вы хотите описать в комментариях xml-документации), используйте стандартный механизм кавычения (&lt; и &gt;). Чтобы ссылаться на универсальные идентификаторы в элементах ссылки на код (cref), используйте escape-символы (например, cref="List&lt;T&gt;") или фигурные скобки (cref="List{T}"). В качестве специального случая, компилятор анализирует фигурные скобки как угловые, чтобы сделать комментарий к документации менее трудоемким для автора при обращении к универсальным идентификаторам.

Примечание.

Если вы пишете комментарии с помощью разделителя комментариев XML одной строки, но не включают теги, ///компилятор добавляет текст этих примечаний в выходной XML-файл. Однако выходные данные не включают XML-элементы, такие как <summary>. Большинство средств, использующих XML-комментарии (включая IntelliSense Visual Studio), не читают эти комментарии.

Средства, принимаюющие входные данные XML-документации

Следующие средства создают выходные данные из XML-комментариев:

  • DocFX: DocFX — это генератор документации по API для .NET, который в настоящее время поддерживает C#, Visual Basic и F#. Он также позволяет настроить созданную справочную документацию. DocFX создает статический HTML-сайт из исходного кода и файлов Markdown. Кроме того, DocFX обеспечивает гибкость в настройке макета и стиля веб-сайта с помощью шаблонов. Вы также можете создавать пользовательские шаблоны.
  • Sandcastle: средства Sandcastle создают файлы справки для библиотек управляемых классов, содержащих как концептуальные, так и справочные страницы API. Средства Sandcastle работают на основе командной строки и не имеют интерфейса графического пользователя, функций управления проектами или автоматизированного процесса сборки. Построитель файлов справки Sandcastle предоставляет автономные графические интерфейсы и средства на основе командной строки для создания файла справки автоматически. Пакет интеграции Visual Studio также доступен для него, чтобы помочь проектам создавать и управлять ими полностью из Visual Studio.
  • Doxygen: Doxygen создает веб-браузер документации (в HTML) или автономное справочное руководство (в LaTeX) из набора документированных исходных файлов. Кроме того, поддерживается создание выходных данных в RTF (MS Word), PostScript, гиперссылочных PDF, сжатых HTML, DocBook и страниц руководства Unix. Можно настроить Doxygen для извлечения структуры кода из незадокументированных исходных файлов.

Примечание.

Комментарии xml-документации не являются метаданными. Компилятор не включает их в скомпилированную сборку, поэтому они недоступны через отражение.

Строки идентификатора

Компилятор записывает каждый тип или член в элемент в выходном XML-файле. Каждый элемент имеет уникальную строку идентификатора, которая идентифицирует тип или элемент. Строка идентификатора содержит сведения о операторах, параметрах, возвращаемых значениях, параметрах универсального типа, refinи out параметрах. Чтобы закодировать все эти потенциальные элементы, компилятор следует четко определенным правилам для создания строк идентификатора. Программы, обрабатывающие XML-файл, используют строку идентификатора, чтобы определить соответствующие метаданные или элемент отражения .NET, к которому применяется документация.

Компилятор следует этим правилам при создании строк идентификатора:

  • Строка не содержит пробелов.

  • Строка начинается с одного символа и двоеточия, определяющего тип элемента. Используйте следующие типы элементов:

    Персонаж Тип участника Примечания.
    N пространство имен Вы не можете добавлять документационные комментарии в пространство имен, но вы можете делать ссылки cref на них, если это поддерживается.
    T тип Тип — это класс, интерфейс, структура, перечисление или делегат.
    F поле
    P свойство Включает индексаторы или другие индексированные свойства.
    M метод Включает специальные методы, такие как конструкторы и операторы.
    E событие
    ! Строка ошибки Остальная часть строки содержит сведения об ошибке. Компилятор C# создает сведения об ошибке для ссылок, которые не могут быть разрешены.
  • Вторая часть строки — это полностью квалифицированное имя элемента, начиная с корня пространства имен. Имя элемента, его вложенные типы и пространство имен разделяются точками. Если имя самого элемента имеет периоды, компилятор заменяет их хэш-знаком ('#). В грамматике предполагается, что у элемента нет хэш-входа непосредственно в его имя. Например, полное имя конструктора String — System.String.#ctor.

  • Для свойств и методов следует список параметров, заключенный в скобки. Если нет параметров, круглые скобки отсутствуют. Параметры разделены запятыми. Кодировка каждого параметра следует непосредственно тому, как он закодирован в сигнатуре .NET (см. Microsoft.VisualStudio.CorDebugInterop.CorElementType для определений всех элементов, написанных заглавными буквами, в следующем списке):

    • Базовые типы. Регулярные типы (ELEMENT_TYPE_CLASS или ELEMENT_TYPE_VALUETYPE) представляются как полное имя типа.
    • Встроенные типы, такие как ELEMENT_TYPE_I4, ELEMENT_TYPE_OBJECT, ELEMENT_TYPE_TYPEDBYREFELEMENT_TYPE_STRINGиELEMENT_TYPE_VOID, представляются как полное имя соответствующего полного типа. Например, System.Int32 или System.TypedReference.
    • ELEMENT_TYPE_PTR обозначается символом "*", следующим за измененным типом.
    • ELEMENT_TYPE_BYREF обозначается как "@" после измененного типа.
    • ELEMENT_TYPE_CMOD_OPT обозначается как '!' и полное имя класса модификатора, следующее за измененным типом.
    • ELEMENT_TYPE_SZARRAY представляется как "[]" после типа элемента массива.
    • ELEMENT_TYPE_ARRAY представляется как [нижняя граница:size,нижняя граница:size], где число запятых — 1, а нижние границы и размер каждого измерения, если известно, представлены в десятичном разряде. Нижние границы и размер опущены, если они не указаны. Если нижняя граница и размер для определенного измерения опущены, то ":" также не отображается. Например, двухмерный массив с 1 в качестве нижних границ и неопределенных размеров равен [1:,1:].
  • Только для операторов преобразования (op_Implicit и op_Explicit) возвращаемое значение метода закодировано как ~ за типом возвращаемого значения. Например, <member name="M:System.Decimal.op_Explicit(System.Decimal arg)~System.Int32"> — это тег для оператора public static explicit operator int (decimal value); приведения, объявленного в классе System.Decimal.

  • Для универсальных типов за именем типа следует апостроф, а затем число, указывающее количество параметров универсального типа. Например, <member name="T:SampleClass`2"> тег для типа, определенного как public class SampleClass<T, U>. Для методов, которые принимают универсальные типы в качестве параметров, параметры универсального типа указываются в виде чисел, используя обратные апострофы (например, `0,`1). Каждое число представляет нотацию массива на основе нуля для универсальных параметров типа.

    • ELEMENT_TYPE_PINNED обозначается как "^" после модифицированного типа. Компилятор C# никогда не создает эту кодировку.
    • ELEMENT_TYPE_CMOD_REQ представляется как "|" и полное имя класса модификатора после измененного типа. Компилятор C# никогда не создает эту кодировку.
    • ELEMENT_TYPE_GENERICARRAY представляется как "[?]" после типа элемента массива. Компилятор C# никогда не создает эту кодировку.
    • ELEMENT_TYPE_FNPTRпредставляется как "=FUNC:type(signature)", где является тип возвращаемого значения, а type — аргументы метода. Если аргументов нет, скобки опущены. Компилятор C# никогда не создает эту кодировку.
    • Следующие компоненты подписи не представлены, так как они не используются для различения перегруженных методов:
      • Соглашение о вызовах
      • тип возвращаемого значения
      • ELEMENT_TYPE_SENTINEL

В следующих примерах показано, как компилятор создает строки идентификатора для класса и его членов:

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

Спецификация языка C#

Дополнительные сведения см. в приложении спецификации языка C# по комментариям к документации.