Comentários da documentação XML

Os arquivos de origem C# podem ter comentários estruturados que produzem a documentação da API para os tipos definidos nesses arquivos. O compilador C# produz um arquivo XML que contém dados estruturados que representam os comentários e as assinaturas de API. Outras ferramentas podem processar essa saída XML para criar uma documentação legível na forma de páginas da Web ou arquivos PDF, por exemplo.

Esse processo oferece muitas vantagens para você adicionar a documentação da API no código:

  • O compilador C# combina a estrutura do código C# com o texto dos comentários em um único documento XML.
  • O compilador C# verifica se os comentários correspondem às assinaturas da API para marcas relevantes.
  • As ferramentas que processam os arquivos de documentação XML podem definir elementos XML e atributos específicos dessas ferramentas.

Ferramentas como o Visual Studio fornecem o IntelliSense para muitos elementos XML comuns usados em comentários de documentação.

Este artigo aborda estes tópicos:

  • Comentários de documentação e geração de arquivos XML
  • Marcas validadas pelo compilador C# e pelo Visual Studio
  • Formato do arquivo XML gerado

Criar saída de documentação XML

Crie a documentação do código gravando campos de comentário especiais indicados por barras triplas. Os campos de comentário incluem elementos XML que descrevem o bloco de código que segue os comentários. Por exemplo:

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

Você define a opção GenerateDocumentationFile ou DocumentationFile e o compilador localizará todos os campos de comentário com marcas XML no código-fonte e criará um arquivo de documentação XML com base nesses comentários. Quando essa opção está habilitada, o compilador gera o aviso CS1591 para qualquer membro publicamente visível declarado no projeto sem comentários da documentação XML.

Formatos de comentário XML

O uso de comentário da documentação XML requer delimitadores, que indicam onde um comentário da documentação começa e termina. Você usa os seguintes delimitadores com as marcas de documentação XML:

  • /// Delimitador de linha única: os exemplos de documentação e modelos de projeto em C# usam esse formulário. Se houver um espaço em branco após o delimitador, ele não será incluído na saída XML.

    Observação

    O Visual Studio insere automaticamente as marcas <summary> e </summary> e posiciona o cursor nessas marcas após você digitar o delimitador /// no editor de código. Você pode ativar ou desativar esse recurso na caixa de diálogo Opções.

  • /** */ Delimitadores multilinha: os delimitadores/** */ têm as seguintes regras de formatação:
    • Na linha que contém o delimitador /**, se o resto da linha for um espaço em branco, a linha não será processada para comentários. Se o primeiro caractere após o delimitador /** for um espaço em branco, esse caractere de espaço em branco será ignorado e o restante da linha será processado. Caso contrário, todo o texto da linha após o delimitador /** é processado como parte do comentário.

    • Na linha que contém o delimitador */, se houver apenas espaços em branco até o delimitador */, essa linha será ignorada. Caso contrário, o texto na linha até o delimitador */ é processado como parte do comentário.

    • Para as linhas após a que começa com o delimitador /**, o compilador procura um padrão comum no início de cada linha. O padrão pode consistir de espaço em branco opcional e um asterisco (*), seguido de mais espaço em branco opcional. Se o compilador encontrar um padrão comum no início de cada linha que não começa com o delimitador /** ou termina com o delimitador */, ele ignorará esse padrão para cada linha.

    • A única parte do comentário a seguir que será processada é a linha que começa com <summary>. Os três formatos de marca produzem os mesmos comentários.

      /** <summary>text</summary> */
      
      /**
      <summary>text</summary>
      */
      
      /**
      * <summary>text</summary>
      */
      
    • O compilador identifica um padrão comum de " * " no início da segunda e terceira linhas. O padrão não é incluído na saída.

      /**
      * <summary>
      * text </summary>*/
      
    • O compilador não encontra nenhum padrão comum no seguinte comentário porque o segundo caractere na terceira linha não é um asterisco. Todo o texto na segunda e terceira linhas é processado como parte do comentário.

      /**
      * <summary>
         text </summary>
      */
      
    • O compilador não encontra nenhum padrão no seguinte comentário por dois motivos. Primeiro, o número de espaços antes do asterisco não é consistente. Segundo, a quinta linha começa com uma guia, que não coincide com espaços. Todo o texto das linhas de dois a cinco é processado como parte do comentário.

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

Para consultar elementos XML (por exemplo, sua função processa elementos XML específicos que você deseja descrever em um comentário da documentação XML), você pode usar o mecanismo de citação padrão (&lt; e &gt;). Para consultar identificadores genéricos em elementos de referência de código (cref), você pode usar os caracteres de escape (por exemplo, cref="List&lt;T&gt;") ou chaves (cref="List{T}"). Como um caso especial, o compilador analisa as chaves como colchetes angulares para tornar o comentário da documentação menos incômodo para o autor ao fazer referência a identificadores genéricos.

Observação

Os comentários da documentação XML não são metadados; eles não estão incluídos no assembly compilado e, portanto, não são acessíveis através de reflexão.

Ferramentas que aceitam a entrada da documentação XML

As seguintes ferramentas criam a saída com base em comentários XML:

  • DocFX: DocFX é um gerador de documentação de API para .NET, que atualmente dá suporte a C#, Visual Basic e F#. Ele também permite que você personalize a documentação de referência gerada. O DocFX cria um site HTML estático com base no código-fonte e nos arquivos Markdown. Além disso, o DocFX fornece a flexibilidade para personalizar o layout e o estilo do site por meio de modelos. Você também pode criar modelos personalizados.
  • Sandcastle: as ferramentas do Sandcastle criam arquivos de ajuda para bibliotecas de classes gerenciadas que contêm páginas de referência conceituais e de API. As ferramentas do Sandcastle são baseadas em linha de comando e não possuem front-end de GUI, recursos de gerenciamento de projeto ou processo de build automatizado. O Construtor de Arquivo de Ajuda Sandcastle fornece GUI autônomo e ferramentas baseadas em linha de comando para criar um arquivo de ajuda de forma automatizada. Um pacote de integração do Visual Studio também está disponível para que os projetos de ajuda possam ser criados e gerenciados inteiramente no Visual Studio.
  • Doxygen: o Doxygen gera um navegador de documentação online (em HTML) ou um manual de referência offline (no LaTeX) de um conjunto de arquivos de origem documentados. Também há suporte para gerar saída nas páginas de manual do RTF (MS Word), PostScript, PDF com hyperlink, HTML compactado, DocBook e Unix. Você pode configurar o Doxygen para extrair a estrutura de código de arquivos de origem não documentados.

Cadeias de caracteres de ID

Cada tipo ou membro é armazenado em um elemento no arquivo XML de saída. Cada um desses elementos tem uma cadeia de caracteres de ID exclusiva que identifica o tipo ou membro. A cadeia de caracteres de ID deve responder por operadores, parâmetros, valores retornados, parâmetros de tipo genérico e parâmetros ref, in e out. Para codificar todos esses elementos potenciais, o compilador segue regras claramente definidas para gerar as cadeias de caracteres de ID. Programas que processam o arquivo XML usam a cadeia de identificação para identificar o item de metadados ou reflexão do .NET correspondente ao qual a documentação se aplica.

O compilador observa as seguintes regras quando gera as cadeias de identificação:

  • Não há espaços em branco na cadeia de caracteres.

  • A primeira parte da cadeia identifica o tipo de membro usando um único caractere seguido por dois-pontos. São usados os seguintes tipos de membro:

    Caractere Tipo de membro Observações
    N namespace Não é possível adicionar comentários de documentação a um namespace, mas será possível fazer referências cref a eles se houver suporte.
    T tipo Um tipo é uma classe, interface, struct, enumeração ou delegado.
    F field
    P propriedade Inclui indexadores ou outras propriedades indexadas.
    M method Inclui métodos especiais, como construtores e operadores.
    E event
    ! cadeia de caracteres de erro O restante da cadeia de caracteres fornece informações sobre o erro. O compilador C# gera informações de erro para links que não podem ser resolvidos.
  • A segunda parte da cadeia de caracteres é o nome totalmente qualificado do item, iniciando na raiz do namespace. O nome do item, seus tipos delimitadores e o namespace são separados por pontos. Se o nome do próprio item tiver pontos, eles serão substituídos pelo sustenido ('#'). Supõe-se que nenhum item tem um sustenido diretamente em seu nome. Por exemplo, o nome totalmente qualificado do construtor de cadeia de caracteres é "System.String.#ctor".

  • Para propriedades e métodos, segue a lista de parâmetros entre parênteses. Se não houver parâmetros, não haverá parênteses. Os parâmetros são separados por vírgulas. A codificação de cada parâmetro segue diretamente como ele é codificado em uma assinatura .NET (Consulte Microsoft.VisualStudio.CorDebugInterop.CorElementType para obter as definições de todos os elementos de caps na lista a seguir):

    • Tipos base. Tipos regulares (ELEMENT_TYPE_CLASS ou ELEMENT_TYPE_VALUETYPE) são representados como o nome totalmente qualificado do tipo.
    • Tipos intrínsecos (por exemplo, ELEMENT_TYPE_I4, ELEMENT_TYPE_OBJECT, ELEMENT_TYPE_STRING, ELEMENT_TYPE_TYPEDBYREF e ELEMENT_TYPE_VOID) são representados como o nome totalmente qualificado do tipo completo correspondente. Por exemplo, System.Int32 ou System.TypedReference.
    • ELEMENT_TYPE_PTR é representado como um '*' após o tipo modificado.
    • ELEMENT_TYPE_BYREF é representado como um '@' após o tipo modificado.
    • ELEMENT_TYPE_CMOD_OPT é representado como um '!' e o nome totalmente qualificado da classe do modificador, após o tipo modificado.
    • ELEMENT_TYPE_SZARRAY é representado como "[]" após o tipo de elemento da matriz.
    • ELEMENT_TYPE_ARRAY é representado como [lowerbound:size,lowerbound:size] em que o número de vírgulas é a classificação -1 e os limites e o tamanho inferiores de cada dimensão, se conhecidos, são representados no formato decimal. Se um limite inferior ou tamanho não for especificado, ele será omitido. Se o limite e o tamanho inferiores de uma determinada dimensão forem omitidos, o ':' será omitido também. Por exemplo, uma matriz bidimensional com 1 como limites inferiores e tamanhos não especificados é [1:,1:].
  • Somente para operadores de conversão (op_Implicit e op_Explicit), o valor retornado do método é codificado como um ~ seguido pelo tipo de retorno. Por exemplo: <member name="M:System.Decimal.op_Explicit(System.Decimal arg)~System.Int32"> é a marca do operador de conversão public static explicit operator int (decimal value); declarado na classe System.Decimal.

  • Para tipos genéricos, o nome do tipo é seguido por um caractere de acento grave e, em seguida, por um número que indica o número de parâmetros de tipo genérico. Por exemplo: <member name="T:SampleClass``2"> é a marcação de um tipo definido como public class SampleClass<T, U>. Para métodos que aceitam tipos genéricos como parâmetros, os parâmetros de tipo genérico são especificados como números precedidos por caracteres de acento grave (por exemplo `0,`1). Cada número representa uma notação de matriz com base em zero para parâmetros genéricos do tipo.

    • ELEMENT_TYPE_PINNED é representado como um '^' após o tipo modificado. O compilador C# nunca gera essa codificação.
    • ELEMENT_TYPE_CMOD_REQ é representado como um '!' e o nome totalmente qualificado da classe do modificador, após o tipo modificado. O compilador C# nunca gera essa codificação.
    • ELEMENT_TYPE_GENERICARRAY é representado como "[?]" após o tipo de elemento da matriz. O compilador C# nunca gera essa codificação.
    • ELEMENT_TYPE_FNPTR é representado como "=FUNC:type(signature)", em que type é o tipo de retorno e assinatura são os argumentos do método. Se não houver nenhum argumento, os parênteses serão omitidos. O compilador C# nunca gera essa codificação.
    • Os seguintes componentes de assinatura não são representados, porque não são usadas para diferenciar métodos sobrecarregados:
      • convenção de chamada
      • tipo de retorno
      • ELEMENT_TYPE_SENTINEL

Os exemplos a seguir mostram como as cadeias de identificação de uma classe e seus membros são geradas:

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

Especificação da linguagem C#

Para obter mais informações, consulte o anexo Especificação da linguagem C# nos comentários da documentação.