Herencia de comentarios para C # (en realidad, cualquier idioma)

93

Supongamos que tengo esta interfaz

public interface IFoo
{
    ///<summary>
    /// Foo method
    ///</summary>
    void Foo();

    ///<summary>
    /// Bar method
    ///</summary>
    void Bar();

    ///<summary>
    /// Situation normal
    ///</summary>
    void Snafu();
}

Y esta clase

public class Foo : IFoo
{
    public void Foo() { ... }
    public void Bar() { ... }
    public void Snafu() { ... }
}

¿Hay alguna manera o hay una herramienta que me permita poner automáticamente los comentarios de cada miembro en una clase o interfaz base?

¡Porque odio volver a escribir los mismos comentarios para cada subclase derivada!

jumpinjackie
fuente
14
No solo lo odio, sino que también es difícil mantenerlos sincronizados.
Olivier Jacot-Descombes

Respuestas:

17

GhostDoc hace exactamente eso. Para los métodos que no se heredan, intenta crear una descripción a partir del nombre.

FlingThing() se convierte en "Flings the Thing"

James Curran
fuente
2
GhostDoc es increíble, una de esas cosas que no sabía que necesitaba pero que ahora no puedo prescindir: o)
NikolaiDante
180
Los documentos generados automáticamente me parecen una muy mala idea. No agregan ninguna información útil, solo amplían el código innecesariamente. Si una herramienta puede entender lo que hace un método por su nombre, entonces una persona también puede entender y no se necesita ningún documento.
Lensflare
8
@Lensflare Esto es tan cierto. Una vez tuve que usar un marco que solo tenía comentarios generados, que NO agregaban información al método / clase. En lugar de "Este método hace esto y aquello", los comentarios eran como "Este es el método XY de la clase Z". xD Además, no podía navegar por el código, por lo que se redujo a prueba y error. ¡Nunca más! :-)
itmuckel
15
@Lensflare Mientras que el 100% de acuerdo con usted en lo que confiar en los AGDs como es , debo señalar que AGDs no están destinados a ser utilizados como "hacer todo" botones mágicos por el estilo. En cambio, están destinados a ser utilizados como generadores de plantillas para reducir la cantidad de documentación repetitiva y repetitiva que tiene que escribir usted mismo, para que pueda concentrarse en las cosas importantes. --- Por ejemplo, puede generar los <summary>, <param>, <returns>, <throws>, etc...secciones para ti. Muchas veces con resultados suficientemente buenos; otras veces necesitando correcciones o ampliando, pero aún reduciendo el esfuerzo general.
XenoRo
5
gente, la documentación no es para desarrolladores, es para arquitectos, así que sus traseros están cubiertos: "Oye, ¿podemos leer la documentación del código de tu proyecto? Claro, aquí está".
Trident D'Gao
151

Siempre puedes usar la <inheritdoc />etiqueta.

public class Foo : IFoo
{
    /// <inheritdoc />
    public void Foo() { ... }
    /// <inheritdoc />
    public void Bar() { ... }
    /// <inheritdoc />
    public void Snafu() { ... }
}
Vadim
fuente
7
No sabía que <hereitdoc /> existiera ... Pero por lo que puedo ver, el comentario de este método no aparece con intellisense.
gerleim
12
@gerleim Mira la respuesta de Jeff Heaton de un año antes y el comentario debajo. Sandcastle tiene <hereitdoc />, no C #.
rbwhitaker
4
Veo comentarios de la interfaz en intellisense con hereitdoc, y también si no hay ningún code-doc en la clase derivada. Pero eso podría deberse a que tengo resharper.
Tim Abell
9
Resharper 2017.2 ha mejorado el soporte para heritagedoc jetbrains.com/resharper/whatsnew
Dav Evans
3
Visual Studio Enterprise 2017 (versión 15.9.3) no me muestra comentarios heredados.
herzbube
26

Úselo /// <inheritdoc/>si desea herencia. Evite GhostDoc o cualquier cosa por el estilo.

Estoy de acuerdo en que es molesto que los comentarios no se hereden. Sería un complemento bastante simple de crear si alguien tuviera tiempo (desearía tenerlo).

Dicho esto, en nuestra base de código colocamos comentarios XML solo en las interfaces y agregamos comentarios de implementación adicionales a la clase. Esto funciona para nosotros ya que nuestras clases son privadas / internas y solo la interfaz es pública. Cada vez que usamos los objetos a través de las interfaces, los comentarios completos se muestran en intellisence.

GhostDoc es un buen comienzo y ha facilitado el proceso de escribir comentarios. Es especialmente útil mantener los comentarios actualizados cuando agrega / elimina parámetros, vuelve a ejecutar GhostDoc y actualizará la descripción.

Dennis
fuente
Estoy confundido: dijiste que evitaras GhostDoc, pero al final aparentemente respaldaste a GhostDoc para facilitar las cosas. ¿Puede aclarar lo que quiere decir?
Mike Marynowski
Gracias @MikeMarynowski. Este es un viejo consejo. Creo que quería decir en ese momento que GhostDoc, como cualquier otro generador, agregará comentarios pero con detalles casi inútiles, por ejemplo <param name="origin">The origin.</param>. Vea ghostdoc dice las cosas más malditas para más ejemplos. Visual Studio ahora tiene mucho mejor linting y generadores para xmldocs para avisarle cuando los parámetros + documentos no se alinean, por lo que GhostDoc (u otras herramientas) ya no se necesitan.
Dennis
15

Java tiene esto y lo uso todo el tiempo. Solo haz:

/**
 * {@inheritDoc}
 */

Y la herramienta Javadoc lo resuelve.

C # tiene un marcador similar:

<inheritDoc/>

Puede leer más aquí:

http://www.ewoodruff.us/shfbdocs/html/79897974-ffc9-4b84-91a5-e50c66a0221d.htm

JeffHeaton
fuente
37
C # no tiene el <inheritdoc/>marcador: Sandcastle lo tiene. shfb.codeplex.com
Eric Dand
8
Existe una solicitud de función de voz del usuario para agregar <hereitdoc /> a C #. Sube-voto al visualstudio.uservoice.com/forums/121579-visual-studio/...
deadlydog
1
Ni C # ni Java (ni ningún otro lenguaje de programación) tiene ninguno de los elementos "XML doc". Estos son comentarios . Los compiladores no saben nada sobre ellos. Todos ellos son estrictamente utilizados por generadores de documentación de terceros, ya sea javadoc o sandcastle o lo que sea.
James Curran
4
Cuando se indica Java o C #, generalmente significa la comunidad de herramientas asociadas. Ni Java ni C # tienen mucha capacidad en un sentido muy literal. Sería un argumento académico afirmar que Java o C # carecen de la capacidad de conectarse a una base de datos, porque la biblioteca de tiempo de ejecución lo hace.
JeffHeaton
2
¡La versión 16.4.0 de Visual Studio y las posteriores proporcionan intellisense para <hereitDoc />! docs.microsoft.com/en-us/visualstudio/releases/2019/…
ashbygeek
10

Yo diría que use directamente el

/// <inheritdoc cref="YourClass.YourMethod"/>  --> For methods inheritance

Y

/// <inheritdoc cref="YourClass"/>  --> For directly class inheritance

Tienes que poner estos comentarios solo en la línea anterior de tu clase / método

Esto obtendrá la información de sus comentarios, por ejemplo, de una interfaz que haya documentado como:

    /// <summary>
    /// This method is awesome!
    /// </summary>
    /// <param name="awesomeParam">The awesome parameter of the month!.</param>
    /// <returns>A <see cref="AwesomeObject"/> that is also awesome...</returns>
    AwesomeObject CreateAwesome(WhateverObject awesomeParam);
Gatsby
fuente
¡Gracias por el consejo! Este enfoque es más explícito y resuelve el problema de la descripción de la clase de herencia de la clase de objeto (incluso cuando se implementa la interfaz).
Denis Babarykin
8

Resharper tiene una opción para copiar los comentarios de la clase base o interfaz.

svick
fuente
1
¿Oh? ¿Cómo? Yo uso ReSharper y nunca vi esa opción al implementar o heredar una interfaz ... ¿Dónde está y cómo se usa esa opción?
Jazimov
2
@Jazimov Cuando Alt + Ingresa el método de anulación, hay una opción para "Copiar documentación desde la base".
svick
8

Otra forma es utilizar la <see />etiqueta de documentación XML. Este es un esfuerzo adicional, pero funciona fuera de la caja ...

Aquí hay unos ejemplos:

/// <summary>
/// Implementation of <see cref="IFoo"/>.
/// </summary>
public class Foo : IFoo
{
    /// <summary>
    /// See <see cref="IFoo"/>.
    /// </summary>
    public void Foo() { ... }

    /// <summary>
    /// See <see cref="IFoo.Bar"/>
    /// </summary>
    public void Bar() { ... }

    /// <summary>
    /// This implementation of <see cref="IFoo.Snafu"/> uses the a caching algorithm for performance optimization.
    /// </summary>
    public void Snafu() { ... }
}

Actualizar:

Ahora prefiero usar lo /// <inheritdoc/>que ahora es compatible con ReSharper.

Mathias Rotter
fuente
1

Terminé creando una herramienta para posprocesar los archivos de documentación XML para agregar soporte para reemplazar la <inheritdoc/>etiqueta en los archivos de documentación XML. Disponible en www.inheritdoc.io (versión gratuita disponible).

K Johnson
fuente
0

Bueno, hay una especie de solución nativa que encontré para .NET Core 2.2

La idea es usar <include>etiqueta.

Puedes agregar <GenerateDocumentationFile>true</GenerateDocumentationFile>tu.csproj archivo.

Es posible que tenga una interfaz:

namespace YourNamespace
{
    /// <summary>
    /// Represents interface for a type.
    /// </summary>
    public interface IType
    {
        /// <summary>
        /// Executes an action in read access mode.
        /// </summary>
        void ExecuteAction();
    }
}

Y algo que hereda de ella:

using System;

namespace YourNamespace
{
    /// <summary>
    /// A type inherited from <see cref="IType"/> interface.
    /// </summary>
    public class InheritedType : IType
    {
        /// <include file='bin\Release\netstandard2.0\YourNamespace.xml' path='doc/members/member[@name="M:YourNamespace.IType.ExecuteAction()"]/*'/>
        public void ExecuteAction() => Console.WriteLine("Action is executed.");
    }
}

Ok, da un poco de miedo, pero agrega los elementos esperados al YourNamespace.xml.

Si se construye Debugconfiguración, se puede intercambiar Releasepara Debugel fileatributo de la includeetiqueta.

Para encontrar una referencia correcta member, namesimplemente abra el Documentation.xmlarchivo generado .

También asumo que este enfoque requiere que un proyecto o solución se compile al menos dos veces (la primera vez para crear un archivo XML inicial y la segunda para copiar elementos de él a sí mismo).

El lado positivo es que Visual Studio valida los elementos copiados, por lo que es mucho más fácil mantener la documentación y el código sincronizados con la interfaz / clase base, etc. (por ejemplo, nombres de argumentos, nombres de parámetros de tipo, etc.).

En mi proyecto, terminé con ambos <inheritdoc/>(para DocFX) y <include/>(Para publicar paquetes NuGet y para validación en Visual Studio):

        /// <inheritdoc />
        /// <include file='bin\Release\netstandard2.0\Platform.Threading.xml' path='doc/members/member[@name="M:Platform.Threading.Synchronization.ISynchronization.ExecuteReadOperation(System.Action)"]/*'/>
        public void ExecuteReadOperation(Action action) => action();
Konard
fuente