Compartir a través de


Generación de comentarios de documentación de LA API XML

Los archivos de código fuente de C# pueden incluir comentarios estructurados que generan documentación de API para los tipos definidos en esos archivos. El compilador de C# genera un archivo XML que contiene datos estructurados que representan los comentarios y las firmas de API. Otras herramientas pueden procesar esa salida XML para crear documentación legible en forma de páginas web o archivos PDF, por ejemplo.

Este proceso proporciona muchas ventajas para agregar documentación de API en el código:

  • El compilador de C# combina la estructura del código de C# con el texto de los comentarios en un único documento XML.
  • El compilador de C# comprueba que los comentarios coinciden con las firmas de API para las etiquetas pertinentes.
  • Las herramientas que procesan los archivos de documentación XML pueden definir elementos XML y atributos específicos de esas herramientas.

Las herramientas como Visual Studio proporcionan IntelliSense para muchos elementos XML comunes que se usan en los comentarios de documentación.

En este artículo se tratan estos temas:

  • Comentarios de documentación y generación de archivos XML
  • Etiquetas validadas por el compilador de C# y Visual Studio
  • Formato del archivo XML generado

Creación de una salida de documentación XML

Para crear documentación para el código, escriba campos de comentario especiales indicados por barras diagonales triples. Los campos de comentario incluyen elementos XML que describen el bloque de código que sigue a los comentarios. Por ejemplo:

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

Establezca la opción GenerateDocumentationFile o DocumentationFile y el compilador busca todos los campos de comentario con etiquetas XML en el código fuente y crea un archivo de documentación XML a partir de esos comentarios. Cuando esta opción está habilitada, el compilador genera la advertencia CS1591 para cualquier miembro visible públicamente declarado en el proyecto sin comentarios de documentación XML.

Formatos de comentario XML

El uso de comentarios de documentos XML requiere delimitadores que indican dónde comienza y termina un comentario de documentación. Use los delimitadores siguientes con las etiquetas de documentación XML:

  • /// Delimitador de una sola línea: los ejemplos de documentación y las plantillas de proyecto de C# usan este formulario. Si el espacio en blanco sigue al delimitador, no se incluye en la salida XML.

    Nota:

    Visual Studio inserta automáticamente las etiquetas y </summary> coloca el <summary> cursor dentro de estas etiquetas después de escribir el /// delimitador en el editor de código. Puede activar o desactivar esta característica en el cuadro de diálogo Opciones.

  • /** */ Delimitadores de varias líneas: los /** */ delimitadores tienen las siguientes reglas de formato:
    • En la línea que contiene el /** delimitador, si el resto de la línea es espacio en blanco, la línea no se procesa para los comentarios. Si el primer carácter después del /** delimitador es espacio en blanco, se omite ese carácter de espacio en blanco y se procesa el resto de la línea. De lo contrario, el texto completo de la línea después de que el /** delimitador se procese como parte del comentario.

    • En la línea que contiene el */ delimitador, si solo hay espacios en blanco hasta el */ delimitador, se omite esa línea. De lo contrario, el texto de la línea hasta el */ delimitador se procesa como parte del comentario.

    • Para las líneas después de la que comienza con el /** delimitador, el compilador busca un patrón común al principio de cada línea. El patrón puede constar de espacios en blanco opcionales o un asterisco (*), seguido de más espacios en blanco opcionales. Si el compilador encuentra un patrón común al principio de cada línea que no comienza con el /** delimitador o termina con el */ delimitador, omite ese patrón para cada línea.

    • La única parte del comentario siguiente procesada es la línea que comienza por <summary>. Los tres formatos de etiqueta generan los mismos comentarios.

      /** <summary>text</summary> */
      
      /**
      <summary>text</summary>
      */
      
      /**
      * <summary>text</summary>
      */
      
    • El compilador identifica un patrón común de " * " al principio de las líneas segunda y tercera. El patrón no se incluye en la salida.

      /**
      * <summary>
      * text </summary>*/
      
    • El compilador no encuentra ningún patrón común en el comentario siguiente porque el segundo carácter de la tercera línea no es un asterisco. Todo el texto de la segunda y tercera línea se procesa como parte del comentario.

      /**
      * <summary>
         text </summary>
      */
      
    • El compilador no encuentra ningún patrón en el comentario siguiente por dos motivos. En primer lugar, el número de espacios antes del asterisco no es coherente. En segundo lugar, la quinta línea comienza con una pestaña, que no coincide con espacios. Todo el texto de las líneas dos a cinco se procesa como parte del comentario.

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

Para hacer referencia a elementos XML (por ejemplo, la función procesa elementos XML específicos que desea describir en un comentario de documentación XML), puede usar el mecanismo de comillas estándar (&lt; y &gt;). Para hacer referencia a identificadores genéricos en elementos de referencia de código (cref), puede usar los caracteres de escape (por ejemplo, cref="List&lt;T&gt;") o llaves (cref="List{T}"). Como caso especial, el compilador analiza las llaves como corchetes angulares para que el comentario de documentación sea menos complicado para el autor al hacer referencia a identificadores genéricos.

Nota:

Si escribe comentarios mediante el delimitador de comentario XML de línea única, ///, pero no incluye ninguna etiqueta, el compilador agrega el texto de esos comentarios al archivo de salida XML. Sin embargo, la salida no incluye elementos XML como <summary>. La mayoría de las herramientas que consumen comentarios XML (incluido IntelliSense de Visual Studio) no leen estos comentarios.

Herramientas que aceptan la entrada de documentación XML

Las siguientes herramientas crean resultados a partir de comentarios XML:

  • DocFX: DocFX es un generador de documentación de API para .NET, que actualmente admite C#, Visual Basic y F#. También permite personalizar la documentación de referencia generada. DocFX compila un sitio web HTML estático a partir del código fuente y los archivos Markdown. Además, DocFX le proporciona la flexibilidad para personalizar el diseño y el estilo de su sitio web a través de plantillas. También puede crear plantillas personalizadas.
  • Sandcastle: las herramientas de Sandcastle crean archivos de ayuda para bibliotecas de clases administradas que contienen páginas de referencia conceptuales y api. Las herramientas de Sandcastle se basan en la línea de comandos y no tienen características de front-end de GUI, de administración de proyectos ni de proceso de compilación automatizado. El Generador de archivos de ayuda de Sandcastle proporciona gui independiente y herramientas basadas en línea de comandos para crear un archivo de ayuda de forma automatizada. También hay disponible un paquete de integración de Visual Studio para que los proyectos de ayuda se puedan crear y administrar completamente desde Visual Studio.
  • Doxygen: Doxygen genera un explorador de documentación en línea (en HTML) o un manual de referencia sin conexión (en LaTeX) a partir de un conjunto de archivos de origen documentados. También se admite la generación de resultados en RTF (MS Word), PostScript, PDF con hipervínculos, HTML comprimido, DocBook y páginas manuales de Unix. Puede configurar Doxygen para extraer la estructura de código de los archivos de origen no documentados.

Nota:

Los comentarios de documentación XML no son metadatos; no se incluyen en el ensamblado compilado y, por lo tanto, no son accesibles a través de la reflexión.

Cadenas de identificador

Cada tipo o miembro se almacena en un elemento del archivo XML de salida. Cada uno de esos elementos tiene una cadena de identificador única que identifica el tipo o miembro. La cadena de identificador debe tener en cuenta operadores, parámetros, valores devueltos, parámetros de tipo genérico, ref, iny out parámetros. Para codificar todos esos posibles elementos, el compilador sigue reglas claramente definidas para generar las cadenas de identificador. Los programas que procesan el archivo XML usan la cadena de identificador para identificar los metadatos o el elemento de reflexión de .NET correspondiente al que se aplica la documentación.

El compilador observa las siguientes reglas cuando genera las cadenas de identificador:

  • No hay ningún espacio en blanco en la cadena.

  • La primera parte de la cadena identifica el tipo de miembro mediante un solo carácter seguido de dos puntos. Se usan los siguientes tipos de miembro:

    Carácter Tipo de miembro Notas
    N Espacio de nombres (namespace) No puede agregar comentarios de documentación a un espacio de nombres, pero puede hacer cref referencias a ellos, donde se admiten.
    T tipo Un tipo es una clase, interfaz, estructura, enumeración o delegado.
    F campo
    P propiedad Incluye indizadores u otras propiedades indizada.
    M método Incluye métodos especiales, como constructores y operadores.
    E evento
    ! cadena de error El resto de la cadena proporciona información sobre el error. El compilador de C# genera información de error para vínculos que no se pueden resolver.
  • La segunda parte de la cadena es el nombre completo del elemento, empezando por la raíz del espacio de nombres. El nombre del elemento, sus tipos envolventes y el espacio de nombres están separados por puntos. Si el nombre del elemento tiene puntos, se reemplazan por el signo hash ('#'). La gramática supone que ningún elemento tiene un inicio de sesión hash directamente en su nombre. Por ejemplo, el nombre completo del constructor String es "System.String.#ctor".

  • En el caso de las propiedades y los métodos, la lista de parámetros entre paréntesis sigue. Si no hay parámetros, no hay paréntesis. Los parámetros están separados por comas. La codificación de cada parámetro sigue directamente cómo se codifica en una firma de .NET (consulte Microsoft.VisualStudio.CorDebugInterop.CorElementType para ver las definiciones de todos los elementos caps de la lista siguiente):

    • Tipos base. Los tipos normales (ELEMENT_TYPE_CLASS o ELEMENT_TYPE_VALUETYPE) se representan como el nombre completo del tipo.
    • Los tipos intrínsecos (por ejemplo, ELEMENT_TYPE_I4, ELEMENT_TYPE_OBJECT, ELEMENT_TYPE_STRING, ELEMENT_TYPE_TYPEDBYREFy ELEMENT_TYPE_VOID) se representan como el nombre completo del tipo completo correspondiente. Por ejemplo, System.Int32 o System.TypedReference.
    • ELEMENT_TYPE_PTR se representa como "*" después del tipo modificado.
    • ELEMENT_TYPE_BYREF se representa como "@" después del tipo modificado.
    • ELEMENT_TYPE_CMOD_OPT se representa como "!" y el nombre completo de la clase modificadora, después del tipo modificado.
    • ELEMENT_TYPE_SZARRAY se representa como "[]" siguiendo el tipo de elemento de la matriz.
    • ELEMENT_TYPE_ARRAY se representa como [límite inferior:size,límite inferior:size] donde el número de comas es el rango - 1, y los límites y el tamaño inferiores de cada dimensión, si se conocen, se representan en decimal. El límite inferior y el tamaño se omiten si no se especifican. Si se omite el límite inferior y el tamaño de una dimensión determinada, también se omite ":". Por ejemplo, una matriz bidimensional con 1 como límites inferiores y tamaños no especificados es [1:,1:].
  • Para los operadores de conversión solo (op_Implicit y op_Explicit), el valor devuelto del método se codifica como seguido ~ del tipo de valor devuelto. Por ejemplo: <member name="M:System.Decimal.op_Explicit(System.Decimal arg)~System.Int32"> es la etiqueta del operador public static explicit operator int (decimal value); de conversión declarado en la System.Decimal clase .

  • Para los tipos genéricos, el nombre del tipo va seguido de un verso y, a continuación, un número que indica el número de parámetros de tipo genérico. Por ejemplo: <member name="T:SampleClass`2"> es la etiqueta de un tipo que se define como public class SampleClass<T, U>. En el caso de los métodos que toman tipos genéricos como parámetros, los parámetros de tipo genérico se especifican como números precedidos de la barra inversa (por ejemplo, '0,'1). Cada número representa una notación de matriz de base cero para los parámetros genéricos del tipo.

    • ELEMENT_TYPE_PINNED se representa como "^" después del tipo modificado. El compilador de C# nunca genera esta codificación.
    • ELEMENT_TYPE_CMOD_REQ se representa como "|" y el nombre completo de la clase modificadora, después del tipo modificado. El compilador de C# nunca genera esta codificación.
    • ELEMENT_TYPE_GENERICARRAY se representa como "[?]" siguiendo el tipo de elemento de la matriz. El compilador de C# nunca genera esta codificación.
    • ELEMENT_TYPE_FNPTR se representa como "=FUNC:type(signature)", donde type es el tipo de valor devuelto y signature es los argumentos del método . Si no hay ningún argumento, se omiten los paréntesis. El compilador de C# nunca genera esta codificación.
    • Los siguientes componentes de firma no se representan porque no se usan para diferenciar los métodos sobrecargados:
      • convención de llamada
      • tipo de valor devuelto
      • ELEMENT_TYPE_SENTINEL

En los ejemplos siguientes se muestra cómo se generan las cadenas de identificador de una clase y sus miembros:

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

Especificación del lenguaje C#

Para obtener más información, consulte el anexo especificación del lenguaje C# sobre los comentarios de documentación.