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


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

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

Этот процесс предоставляет множество преимуществ для добавления документации ПО 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_STRING, ELEMENT_TYPE_TYPEDBYREFи 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# по комментариям к документации.