Comentários de documentação XML

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

Este processo oferece-lhe muitas vantagens para adicionar documentação API no seu código:

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

Ferramentas como Visual Studio fornecem 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 ficheiros XML
  • Etiquetas validadas pelo compilador C# e Visual Studio
  • Formato do ficheiro XML gerado

Criar saída de documentação XML

Cria documentação para o seu código escrevendo campos de comentários especiais indicados por cortes triplos. Os campos de comentários 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 encontrará todos os campos de comentários com tags XML no código fonte e criará um ficheiro de documentação XML a partir desses comentários. Quando esta opção está ativada, o compilador gera o aviso CS1591 para qualquer membro publicamente visível declarado no seu projeto sem comentários de documentação XML.

Formatos de comentário XML

A utilização de comentários de doc XML requer delimiters que indicam onde um comentário de documentação começa e termina. Utiliza os seguintes delimiters com as etiquetas de documentação XML:

  • /// Delimitador de linha única: Os exemplos de documentação e os modelos de projeto C# utilizam este formulário. Se houver espaço branco seguindo o delimiter, não está incluído na saída XML.

    Nota

    Visual Studio insere automaticamente as <summary> etiquetas e </summary> as etiquetas e posicione o cursor dentro destas etiquetas depois de escrever o /// delimiter no editor de código. Pode ligar ou desligar esta função na caixa de diálogo Options.

  • /** */ Delimiters multiline: Os /** */ delimiters têm as seguintes regras de formatação:
    • Na linha que contém o /** delimiter, se o resto da linha é espaço branco, a linha não é processada para comentários. Se o primeiro personagem após o delimiter é o /** espaço branco, esse personagem do espaço branco é ignorado e o resto da linha é processado. Caso contrário, todo o texto da linha após o /** delimiter é processado como parte do comentário.

    • Na linha que contém o */ delimiter, se só há espaço branco até aolimiter */ , essa linha é ignorada. Caso contrário, o texto na linha até ao */ delimiter é processado como parte do comentário.

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

    • A única parte do seguinte comentário que é processado é a linha que começa com <summary>. Os três formatos de tag 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 está incluído na saída.

      /**
      * <summary>
      * text </summary>*/
      
    • O compilador não encontra nenhum padrão comum no seguinte comentário porque o segundo personagem na terceira linha não é um asterisco. Todos os textos da segunda e terceira linhas são processados como parte do comentário.

      /**
      * <summary>
         text </summary>
      */
      
    • O compilador não encontra nenhum padrão no seguinte comentário por duas razões. 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 combina com espaços. Todo o texto das linhas dois a cinco é processado como parte do comentário.

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

Para se referir a elementos XML (por exemplo, a sua função processa elementos XML específicos que pretende descrever num comentário de documentação XML), pode utilizar o mecanismo de citação padrão (&lt; e &gt;). Para se referir a identificadores genéricos em elementos de referência de código (cref) pode utilizar os caracteres de fuga (por exemplo, cref="List&lt;T&gt;") ou os aparelhos (cref="List{T}"). Como um caso especial, o compilador analisa os aparelhos como suportes angulares para tornar a documentação menos complicada para o autor quando se refere a identificadores genéricos.

Nota

Os comentários de documentação XML não são metadados; não estão incluídos na montagem compilada e, portanto, não são acessíveis através de reflexão.

Ferramentas que aceitam entrada de documentação XML

As seguintes ferramentas criam saída a partir de comentários XML:

  • DocFX: DocFX é um gerador de documentação API para .NET, que atualmente suporta C#, Visual Basic e F#. Também permite personalizar a documentação de referência gerada. O DocFX constrói um website HTML estático a partir do seu código fonte e ficheiros Markdown. Além disso, o DocFX oferece-lhe a flexibilidade para personalizar o layout e o estilo do seu website através de modelos. Também pode criar modelos personalizados.
  • Sandcastle: As ferramentas de Sandcastle criam ficheiros de ajuda para bibliotecas de classes geridas que contenham páginas de referência conceptuais e API. As ferramentas Sandcastle são baseadas em linha de comando e não têm front-end GUI, funcionalidades de gestão de projetos ou processo de construção automatizado. O Sandcastle Help File Builder fornece ferramentas autónomas gui e linha de comando para construir um ficheiro de ajuda de forma automatizada. Está também disponível um pacote de integração Visual Studio para que os projetos de ajuda possam ser criados e geridos inteiramente a partir de Visual Studio.
  • Doxygen: O Doxygen gera um browser de documentação on-line (em HTML) ou um manual de referência off-line (em LaTeX) a partir de um conjunto de ficheiros de origem documentados. Há também suporte para gerar saída em RTF (MS Word), PostScript, pdf hiperligado, HTML comprimido, DocBook e unix man. Pode configurar o Doxygen para extrair a estrutura de código de ficheiros de origem não documentados.

Cordas de ID

Cada tipo ou membro é armazenado num elemento no ficheiro XML de saída. Cada um desses elementos tem uma cadeia de identificação única que identifica o tipo ou membro. A cadeia de identificação deve ter em conta os operadores, parâmetros, valores de devolução, parâmetros genéricos do tipo, refine out parâmetros. Para codificar todos esses elementos potenciais, o compilador segue regras claramente definidas para gerar as cordas de ID. Os programas que processam o ficheiro XML utilizam a cadeia de ID para identificar os metadados ou objetos de reflexão correspondentes .NET a que a documentação se aplica.

O compilador observa as seguintes regras quando gera as cordas de ID:

  • Nenhum espaço branco está na corda.

  • A primeira parte da corda identifica o tipo de membro usando um único personagem seguido por um cólon. São utilizados os seguintes tipos de membros:

    Caráter Tipo de membro Notas
    N espaço de nomes Não é possível adicionar comentários de documentação a um espaço de nome, mas pode fazer referências a eles, onde suportado.
    T tipo Um tipo é uma classe, interface, estrutura, enum ou delegado.
    F campo
    P property Inclui indexantes ou outras propriedades indexadas.
    M método Inclui métodos especiais, como construtores e operadores.
    E evento
    ! cadeia de erro O resto da cadeia fornece informações sobre o erro. O compilador C# gera informações de erro para ligações que não podem ser resolvidas.
  • A segunda parte da cadeia é o nome totalmente qualificado do item, começando na raiz do espaço de nome. O nome do item, o seu tipo de enclosing e o espaço de nome são separados por períodos. Se o nome do item em si tiver períodos, são substituídos pelo hash-sign ('#'). Supõe-se que nenhum item tem um sinal de haxixe diretamente em seu nome. Por exemplo, o nome totalmente qualificado do construtor de cordas é "System.String.#ctor".

  • Para propriedades e métodos, segue-se a lista de parâmetros em parênteses. Se não houver parâmetros, não há parênteses presentes. Os parâmetros são separados por vírgulas. A codificação de cada parâmetro segue diretamente como é codificada numa assinatura .NET (Ver Microsoft.VisualStudio.CorDebugInterop.CorElementType definições dos elementos de todas as tampas na lista seguinte):

    • Tipos de base. Os tipos regulares (ELEMENT_TYPE_CLASS ou ELEMENT_TYPE_VALUETYPE) são representados como o nome totalmente qualificado do tipo.
    • Os tipos intrínsecos (por exemplo, ELEMENT_TYPE_I4ELEMENT_TYPE_OBJECT, , , ELEMENT_TYPE_STRINGe ELEMENT_TYPE_TYPEDBYREFELEMENT_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 '*' seguindo o tipo modificado.
    • ELEMENT_TYPE_BYREF é representado como um '@' seguindo o tipo modificado.
    • ELEMENT_TYPE_CMOD_OPT é representado como um '!' e o nome totalmente qualificado da classe modificador, seguindo o tipo modificado.
    • ELEMENT_TYPE_SZARRAY é representado como "[]" seguindo o tipo de elemento da matriz.
    • ELEMENT_TYPE_ARRAY é representado como [lowerbound:size,lowerbound:size] onde o número de vírgulas é a classificação - 1, e os limites inferiores e tamanho de cada dimensão, se conhecido, são representados em decimal. Se um limite inferior ou tamanho não for especificado, é omitido. Se o limite inferior e o tamanho de uma determinada dimensão forem omitidos, o ':' também é omitido. Por exemplo, uma matriz bidimensional com 1 como os limites inferiores e tamanhos não especificados é [1:,1:].
  • Apenas para os operadores de conversão (op_Implicit e op_Explicit), o valor de retorno 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 etiqueta para o operador public static explicit operator int (decimal value); de elenco declarado na System.Decimal classe.

  • Para os tipos genéricos, o nome do tipo é seguido por um backtick e, em seguida, um número que indica o número de parâmetros genéricos do tipo. Por exemplo: <member name="T:SampleClass``2"> é a etiqueta para um tipo que é definido como public class SampleClass<T, U>. Para métodos que tomam os tipos genéricos como parâmetros, os parâmetros genéricos do tipo são especificados como números prefaciados com retrospeções (por exemplo '0,'1). Cada número representa uma notação de matriz baseada em zero para os parâmetros genéricos do tipo.

    • ELEMENT_TYPE_PINNED é representado como um '^' seguindo o tipo modificado. O compilador C# nunca gera esta codificação.
    • ELEMENT_TYPE_CMOD_REQ é representado como um "|" e o nome totalmente qualificado da classe modificada, seguindo o tipo modificado. O compilador C# nunca gera esta codificação.
    • ELEMENT_TYPE_GENERICARRAY é representado como "[?]" seguindo o tipo de elemento da matriz. O compilador C# nunca gera esta codificação.
    • ELEMENT_TYPE_FNPTR é representado como "=FUNC:type(assinatura)", onde type está o tipo de devolução, e a assinatura são os argumentos do método. Se não houver argumentos, os parênteses são omitidos. O compilador C# nunca gera esta codificação.
    • Os seguintes componentes de assinatura não estão representados porque não são usados para diferenciar métodos sobrecarregados:
      • convocação de convenção
      • tipo de retorno
      • ELEMENT_TYPE_SENTINEL

Os exemplos a seguir mostram como as cadeias de ID para 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 linguística C#

Para mais informações, consulte o anexo de Especificação de Idioma C# sobre comentários de documentação.