Sandcastle y los Tags XML para los comentarios en código.

Hola a tod@s,

En el siguiente artículo os voy a explicar como agregar comentarios de forma sencilla con Visual Studio 2005 y luego con la herramienta Sandcastle generar una documentación en formato htm o chm. La finalidad es que si nos acostumbramos a que cada vez que hagamos una clase le añadamos comentarios siguiendo las reglas de los tags XML, podamos generar mas tarde una documentación completamente actualizada y de manera bastante rápida de nuestro proyecto. Y en caso de que usemos un generador de código, todavía es mas sencillo hacerlo.

Si estamos haciendo un proyecto en C# 2005 cuando queremos incorporar un comentario sabemos que se tiene que hacer con "//" pero si añadimos una barra mas nos aparecerá un menú contextual con etiquetas xml que tienen una característica especial:

/// <summary>
/// Esta clase hace una importante función. 
/// </summary>
public class MiClase{}

Los distintos tags que hay por ahora son:

<c> <code> <example> <exception> <include> <list>
<para> <param> <paramref> <permission> <remarks> <returns>
<see> <seealso> <summary> <typeparam> <typeparamref> <value>

Lo que voy a hacer ahora es poneros un ejemplo de como usar estas etiquetas en una clase. He construido una clase con 2 constructores, 5 propiedades y 4 métodos. No he usado todas las etiquetas, pero creo que con este ejemplo os bastará para coger conocimientos sobre el tema y si queréis profundizar siempre podréis seguir la MSDN.

Para poder llevar a cabo este ejemplo he tenido que instalarme la herramienta Sandcastle y luego usar un programa que facilita la tarea SandcastleGUI, he optado por este programa debido a su sencillez y porque es gratuito, para obtenerlo solo hay que registrarse.

Para mas información sobre como usar Sandcastle, herramientas que lo usan, etc. visitad este enlace: http://www.sandcastledocs.com/Wiki%20Pages/Home.aspx

Nota: Otra herramienta que está muy bien es la que podéis encontrar en http://www.codeplex.com/SHFB, lo único que es algo mas compleja que la que yo he usado en este ejemplo y no he encontrado la opción para poder incluir un logo. Lo bueno es que te deja parametrizar mas e incluso tiene una opción para que algunos textos aparezcan en español (pero esta opción no está muy lograda).

Mi clase con los comentarios añadidos me ha quedado así:

using System;
using System.Collections.Generic;
using System.Text;

namespace comentarios
{
    /// <summary>
    /// Clase de ejemplo
    /// </summary>
    /// <remarks>
    /// <para>Con esta clase aprenderemos los pasos básicos para <br/>
    /// crear una buena documentación con Sandcastle.</para>
    /// <img src="Class1.png"></img>
    ///</remarks>
    public class Class1
    {
        /// <summary>
        /// Constructor principal de la clase.
        /// </summary>
        /// <remarks>
        /// <para>El constructor principal no admite parámetros.</para>
        /// </remarks>
        /// <seealso cref="Class1(String, String, Boolean, Int32, DateTime)"/>
        public Class1()
        {
        }

        /// <summary>
        /// Sobrecarga del Constructor en el que se inicializan las propiedades.
        /// </summary>
        /// <example>
        /// <code>
        /// Class1 miClase = new Class1("uno", "dos", 3, true, DateTime.Today);
        /// string p1 = miClase.Propiedad1;
        /// string p2= miClase.Propiedad2;       
        /// </code>
        /// </example>
        /// <remarks>
        /// Este segundo constructor necesita 5 parámetros, los dos primeros de tipo cadena <br/>
        /// el tercero de tipo booleano, el cuarto de tipo entero y el quinto de tipo fecha.
        /// </remarks>
        /// <param name="prop1">Propiedad 1 de tipo cadena</param>
        /// <param name="prop2">Propiedad 2 de tipo cadena</param>
        /// <param name="prop3">Propiedad 3 de tipo booleano</param>
        /// <param name="prop4">Propiedad 4 de tipo entero</param>
        /// <param name="prop5">Propiedad 5 de tipo fecha</param>
        /// <seealso cref="Class1()"/>
        public Class1(string prop1, string prop2, bool prop3, Int32 prop4, DateTime prop5)
        {
            _sPropiedad1 = prop1;
            _sPropiedad2 = prop2;
            _bPropiedad3 = prop3;
            _iPropiedad4 = prop4;
            _dPropiedad5 = prop5;
        }

        /// <summary>
        /// Campo privado de tipo cadena, propiedad 1.
        /// </summary>
        private string _sPropiedad1 = string.Empty;
        /// <summary>
        /// Campo privado de tipo cadena, propiedad 2.
        /// </summary>
        private string _sPropiedad2 = string.Empty;
        /// <summary>
        /// Campo privado de tipo booleano, propiedad 3.
        /// </summary>
        private bool _bPropiedad3 = false;
        /// <summary>
        /// Campo privado de tipo entero, propiedad 4.
        /// </summary>
        private Int32 _iPropiedad4 = 0;
        /// <summary>
        /// Campo privado de tipo fecha, propiedad 5.
        /// </summary>
        private DateTime _dPropiedad5 = DateTime.MinValue;

        /// <summary>
        /// Propiedad pública que obtiene o establece el valor de <c>_sPropiedad1</c>.
        /// </summary>
        /// <remarks>Propiedad pública que obtiene o establece el valor de <c>_sPropiedad1</c></remarks>
        /// <value>Obtiene o establece el valor del miembro _sPropiedad1.</value>
        /// <seealso cref="_sPropiedad1"/>
        public string Propiedad1
        {
            get {
                return _sPropiedad1;
            }
            set{
                _sPropiedad1 = value;
            }
        }

        /// <summary>
        /// Propiedad pública que obtiene o establece el valor de <c>_sPropiedad2</c>.
        /// </summary>
        /// <remarks>Propiedad pública que obtiene o establece el valor de <c>_sPropiedad2</c></remarks>
        /// <value>Obtiene o establece el valor del miembro _sPropiedad2.</value>
        /// <seealso cref="_sPropiedad2"/>
        public string Propiedad2
        {
            get {
                return _sPropiedad2;
            }
            set {
                _sPropiedad2 = value;
            }
        }

        /// <summary>
        /// Propiedad pública que obtiene o establece el valor de <c>_bPropiedad3</c>.
        /// </summary>
        /// <remarks>Propiedad pública que obtiene o establece el valor de <c>_bPropiedad3</c></remarks>
        /// <value>Obtiene o establece el valor del miembro _bPropiedad3.</value>
        /// <seealso cref="_bPropiedad3"/>
        public bool Propiedad3
        {
            get {
                return _bPropiedad3;
            }
            set
            {
                _bPropiedad3 = value;
            }
        }

        /// <summary>
        /// Propiedad pública que obtiene o establece el valor de <c>_iPropiedad4</c>.
        /// </summary>
        /// <remarks>Propiedad pública que obtiene o establece el valor de <c>_iPropiedad4</c></remarks>
        /// <value>Obtiene o establece el valor del miembro _iPropiedad4.</value>
        /// <seealso cref="_iPropiedad4"/>
        public Int32 Propiedad4
        {
            get { return _iPropiedad4; }
            set { _iPropiedad4 = value; }
        }

        /// <summary>
        /// Propiedad pública que obtiene o establece el valor de <c>_dPropiedad5</c>.
        /// </summary>
        /// <remarks>Propiedad pública que obtiene o establece el valor de <c>_dPropiedad5</c></remarks>
        /// <value>Obtiene o establece el valor del miembro _dPropiedad5.</value>
        /// <seealso cref="_dPropiedad5"/>
        public DateTime Propiedad5
        {
            get { return _dPropiedad5; }
            set { _dPropiedad5 = value; }
        }

        /// <summary>
        /// Método público que devuelve un booleano al comparar la longitud <br/>
        /// de los miembros  _sPropiedad1 y _sPropiedad2
        /// </summary>
        /// <returns>Devuelve un booleano</returns>
        public bool Metodo1()
        {
            return (_sPropiedad1.Length < _sPropiedad2.Length);
        }

        /// <summary>
        /// Método privado que establece el valor del miembro _iPropiedad4 <br/>
        /// a la suma de los 2 parámetros pasados.
        /// </summary>
        /// <param name="x">Primer parámetro entero</param>
        /// <param name="y">Segundo parámetro entero</param>
        private void Metodo2(Int32 x, Int32 y)
        {
            _iPropiedad4 = x + y;
        }

        /// <summary>
        /// Método público que llama al método privado Metodo2.
        /// </summary>
        /// <param name="x">Primer parámetro entero</param>
        /// <param name="y">Segundo parámetro entero</param>
        public void Metodo3(Int32 x, Int32 y)
        {
            Metodo2(x, y);           
        }

        /// <summary>
        /// Método públic que devuelve un valor doble obtenido <br/>
        /// a través de la división de dos enteros pasados como parametros.
        /// </summary>
        /// <param name="x">Primer parámetro entero</param>
        /// <param name="y">Segundo parámetro entero.</param>
        /// <returns>Devuelve un doble a partir de división de enteros.</returns>
        /// <exception cref="System.Exception">Se produce una excepción cuando intentamos dividir por cero.</exception>
        public Double Metodo4(Int32 x, Int32 y)
        {
            try
            {
                return x / y;
            }
            catch (Exception ex)
            {
                throw ex;
            }
        }
    }
}

Una vez que tenemos el proyecto con los comentarios pertinentes tenemos que habilitar la opción de que al compilar se cree el fichero XML con los comentarios.

Nota: Es muy importante tener en cuenta que si nuestro proyecto hace referencia a otros assemblies, para que se genere correctamente, dichos assemblies tienen que tener asociado su XML de documentación correspondiente, en caso contrario no garantizo que la documentación creada esté correcta.

Generamos la solución y ya podemos utilizar el Sandcastle a través del programa SandcastleGUI para generarnos nuestra documentación.

Como podemos observar en la figura anterior vamos rellenando la información requerida sobre nuestro proyecto.

En la zona "General" rellenamos la primera casilla con la ruta donde se encuentra/n nuestra/s assembly/is, en la segunda casilla le decimos donde queremos que nos deje la documentación generada, la tercera casilla es para que en caso de que añadamos archivos adjuntos como imágenes las pueda encontrar, en mi caso he incluido la imagen del diagrama de la clase que he creado, en la cuarta casilla le indicamos el/los namespace/s que queremos documentar.
En la zona "Custom" indicamos el nombre del programa, la linea de copyright y en caso de que queramos un logo su ruta.
En la zona "Compilation" le indicamos si sigue una sintaxis de C#, VB o C++ manegado, si queremos que los ficheros generados (cuando es un Website) tengan nombres "amigables" o no (es decir, que los nombres de los htm generados tengan algún significado como F_comentarios_Class1__bPropiedad3.htm o que sea un nombre como si estuviera encriptado), si queremos que nos muestre las propiedades, métodos, etc privados (Document internals), que nos formatee a la sintaxis de C# los ejemplos, si queremos tener enlaces a la MSDN para las clases usadas del framework, y por último en qué formato lo queremos, para el ejemplo que he creado quiero un Website con plantilla Hana y que me cree el árbol de contenidos a la izquierda.
El motivo de que haya querido un Website es que te da la posibilidad de tener un buscador.

Una vez que hayamos puesto todas las opciones con las que queremos que se genere nuestra documentación pulsamos el botón "Start documenting" y eso hace que nos aparezca una ventana de lineas de comando haciendo un montón de cosas.

Cuando se cierra la ventana de lineas de comando ya tenemos generada nuestra documentación, para la opción Website, abrimos con un navegador el archivo index.htm (que es el principal).

Si navegamos a través de los constructores, métodos y propiedades que hemos comentado veremos como se ha formateado las líneas de comentario escritas en el proyecto en esta estupenda documentación. Por ejemplo, aunque no se vea muy bien, gracias a lo que hemos escrito en las etiquetas <sumary> se puede ver reflejado en la descripción de los miembros de la clase:

También podemos usar etiquetas típicas de HTML (pero tratando de hacerlo como si de XML se tratara, por ejemplo la etiqueta <BR> no tiene / final, pero aquí se debe poner quedando <BR/>), e incluso podemos insertar imágenes como se puede apreciar en el siguiente dibujo (ver el código de la clase, los comentarios creados en la declaración de la clase Class1):

Podemos aumentar la calidad de nuestra documentación añadiendo ejemplos prácticos (con las etiquetas <example> y <code>) y que al generarse se nos permite copiar el código como vemos en la siguiente imagen (ver el código de la clase, los comentarios creados en la declaración del segundo constructor):

También se puede mostrar las excepciones que se pueden producir en un método. (ver el código de la clase, los comentarios creados en el método 4).

Como os había comentado, tenemos un buscador que al poner palabras para buscar, en caso de que las encuentre nos indica donde y nos las marca en amarillo:

Para que os quede mas claro, podéis crearos un proyecto, usar la clase que he definido y generar la documentación como os he ensañado, de esta forma podréis navegar por la documentación y ver el por qué de los comentarios que he usado.

Espero que os haya parecido interesante.

4 Responses to Sandcastle y los Tags XML para los comentarios en código.

  1. Ismael dice:

    Gracias por tu artículo. Te enlazaré en uno de los foros internos de http://www.iescesarmanrique.org ya que estamos precisamente dando este tema. Yo había trabajado hasta ahora siempre con NDoc debido a que en mi trabajo sólo usabamos Visual Studio 2003. Pero en el instituto estamos con VS2005 y no funciona NDoc. Había leido algo sobre SandCastle pero nunca lo había usado, además toda la documentación la había encontardo en inglés, así que este artículo tuyo nos será muy útil😉

  2. Carmen dice:

    Ese es el fin de mis artículos, que la gente los pueda usar para aprender, por eso agradezco que te haya gustado y de que se vaya a usar.
     

  3. Martin dice:

    Carmen.
     
    Oye como puedo generar la documentacion de las paginas del proyecto website, si al generar el proyecto le dije que usara archivos separados para el HTML y la CLASS de la pagina.

  4. Carmen dice:

    No entiendo lo que quieres decir.
    Para generar la documentación en formato HTML el propio Sandcastle te crea distintos ficheros htm para cada clase, propiedad, etc.

Responder

Introduce tus datos o haz clic en un icono para iniciar sesión:

Logo de WordPress.com

Estás comentando usando tu cuenta de WordPress.com. Cerrar sesión / Cambiar )

Imagen de Twitter

Estás comentando usando tu cuenta de Twitter. Cerrar sesión / Cambiar )

Foto de Facebook

Estás comentando usando tu cuenta de Facebook. Cerrar sesión / Cambiar )

Google+ photo

Estás comentando usando tu cuenta de Google+. Cerrar sesión / Cambiar )

Conectando a %s

A %d blogueros les gusta esto: