Ereditarietà dei commenti per C # (in realtà qualsiasi linguaggio)


93

Supponiamo che io abbia questa interfaccia

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

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

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

E questa classe

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

Esiste un modo o esiste uno strumento che mi consenta di inserire automaticamente i commenti di ogni membro in una classe o interfaccia base?

Perché odio riscrivere gli stessi commenti per ogni sottoclasse derivata!


13
Non solo lo odio, ma è anche difficile mantenerli sincronizzati.
Olivier Jacot-Descombes

Risposte:


17

GhostDoc fa esattamente questo. Per i metodi che non sono ereditati, cerca di creare una descrizione dal nome.

FlingThing() diventa "Flings the Thing"


2
GhostDoc è fantastico, una di quelle cose di cui non sapevo di aver bisogno ma che ora non posso fare a meno: o)
NikolaiDante

178
I documenti generati automaticamente mi sembrano una pessima idea. Non aggiungono alcuna informazione utile, ma fanno saltare in aria il codice inutilmente. Se uno strumento può capire cosa fa un metodo dal suo nome, allora anche una persona può capire e non è necessario alcun documento.
Lensflare

8
@Lensflare Questo è così vero. Una volta ho dovuto usare un framework che aveva solo tali commenti generati, che NON aggiungeva informazioni al metodo / classe. Invece di "Questo metodo fa questo e quello" i commenti dove come "Questo è il metodo XY di classe Z". xD Inoltre non potevi sfogliare il codice, quindi è passato a tentativi ed errori. Mai più! :-)
itmuckel

15
@Lensflare Anche se sono d'accordo al 100% con te per quanto riguarda gli AGD così com'è , devo sottolineare che gli AGD non sono pensati per essere usati come pulsanti magici "fai tutto" come quello. Invece, sono pensati per essere usati come generatori di modelli per ridurre la quantità di documentazione standard e ripetitiva che devi scrivere da solo, in modo da poterti concentrare sulle cose importanti. --- Ad esempio, può generare il file<summary> , <param>, <returns>, <throws>, etc...sezioni per voi. Molte volte con risultati abbastanza buoni; altre volte necessitano di correzioni o di espansione, ma riducono comunque lo sforzo complessivo.
XenoRo,

4
persone la documentazione non è per gli sviluppatori è per gli architetti, quindi i loro culi sono tutti coperti: "Ehi, possiamo leggere la documentazione del codice del tuo progetto? Certo, eccola qui."
Trident D'Gao

151

Puoi sempre usare <inheritdoc />tag.

public class Foo : IFoo
{
    /// <inheritdoc />
    public void Foo() { ... }
    /// <inheritdoc />
    public void Bar() { ... }
    /// <inheritdoc />
    public void Snafu() { ... }
}

7
Non sapevo nemmeno che <inheritdoc /> esistesse ... Ma per quanto posso vedere, il commento per questo metodo non si presenta con intellisense.
gerleim

12
@gerleim Guarda la risposta di Jeff Heaton dell'anno prima e il commento sotto. Sandcastle ha <inheritdoc />, non C #.
rbwhitaker

4
Vedo commenti dall'interfaccia in intellisense con inheritdoc, e anche se non c'è alcun codice-doc sulla classe derivata. Ma ciò potrebbe essere dovuto al fatto che ho resharper.
Tim Abell

9
Resharper 2017.2 ha migliorato il supporto per inheritdoc jetbrains.com/resharper/whatsnew
Dav Evans

3
Visual Studio Enterprise 2017 (versione 15.9.3) non mostra i commenti ereditati per me.
herzbube

26

Uso /// <inheritdoc/> se vuoi l'eredità. Evita GhostDoc o qualcosa del genere.

Sono d'accordo che sia fastidioso che i commenti non vengano ereditati. Sarebbe un componente aggiuntivo abbastanza semplice da creare se qualcuno avesse il tempo (vorrei averlo fatto).

Detto questo, nella nostra base di codice inseriamo commenti XML solo sulle interfacce e aggiungiamo commenti di implementazione extra alla classe. Questo funziona per noi poiché le nostre classi sono private / interne e solo l'interfaccia è pubblica. Ogni volta che utilizziamo gli oggetti tramite le interfacce, i commenti completi vengono visualizzati nell'intelligenza.

GhostDoc è un buon inizio e ha reso il processo più semplice per scrivere commenti. È particolarmente utile mantenere i commenti aggiornati quando aggiungi / rimuovi parametri, riesegui GhostDoc e aggiornerà la descrizione.


Sono confuso: hai detto di evitare GhostDoc, ma alla fine hai apparentemente approvato GhostDoc per rendere le cose più facili. Puoi chiarire cosa intendi?
Mike Marynowski

Grazie @MikeMarynowski. Questo è un vecchio consiglio. Penso di voler dire al momento che GhostDoc, come qualsiasi altro generatore, aggiungerà commenti ma con dettagli quasi inutili, ad es <param name="origin">The origin.</param>. Vedi ghostdoc dice le cose più dannate per altri esempi. Visual Studio ora ha linting e generatori molto migliori per xmldocs per farti sapere quando i parametri + i documenti non si allineano, quindi GhostDoc (o altri strumenti) non sono più necessari.
Dennis

15

Java ha questo e lo uso sempre. Basta fare:

/**
 * {@inheritDoc}
 */

E lo strumento Javadoc lo capisce.

C # ha un marcatore simile:

<inheritDoc/>

Puoi leggere di più qui:

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


37
C # non ha il <inheritdoc/>marcatore: Sandcastle ce l' ha. shfb.codeplex.com
Eric Dand

8
Esiste una richiesta di funzionalità vocale dell'utente per aggiungere <inheritdoc /> a C #. Vai su, votalo
deadlydog

1
Né C # né Java (né alcun altro linguaggio di programmazione) hanno alcuno degli elementi "XML doc". Questi sono commenti . I compilatori non sanno nulla di loro. Sono tutti rigorosamente utilizzati da generatori di documentazione di terze parti, sia che si tratti di javadoc, sandcastle o altro.
James Curran

4
Quando viene dichiarato Java o C #, di solito si intende la comunità degli strumenti associati. Né Java né C # hanno molte capacità in senso letterale. Sarebbe un argomento accademico affermare che Java o C # non hanno la capacità di connettersi a un database, perché la libreria runtime lo fa.
JeffHeaton

2
Visual Studio versione 16.4.0 e successive forniscono intellisense per <inheritDoc />! docs.microsoft.com/en-us/visualstudio/releases/2019/…
ashbygeek

10

Direi di utilizzare direttamente il file

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

E

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

Devi mettere questi commenti solo sulla riga precedente della tua classe / metodo

Questo otterrà le informazioni dei tuoi commenti, ad esempio, da un'interfaccia che hai documentato come:

    /// <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);

Grazie per il consiglio! Questo approccio è più esplicito e risolve il problema della descrizione della classe di ereditarietà dalla classe di oggetti (anche quando si implementa l'interfaccia).
Denis Babarykin

8

Resharper ha un'opzione per copiare i commenti dalla classe di base o dall'interfaccia.


1
Oh? Come? Uso ReSharper e non ho mai visto quell'opzione durante l'implementazione o l'ereditarietà di un'interfaccia ... Dov'è e come usi questa opzione?
Jazimov

2
@Jazimov Quando si Alt + Invio nel metodo di sovrascrittura, è disponibile un'opzione "Copia documentazione dalla base".
svick

8

Un altro modo è usare il <see /> tag di documentazione XML. Questo è uno sforzo in più ma funziona fuori dagli schemi ...

Ecco alcuni esempi:

/// <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() { ... }
}

Aggiornare:

Ora preferisco usare /// <inheritdoc/>che ora è supportato da ReSharper.


1

Ho finito per creare uno strumento per post-elaborare i file di documentazione XML per aggiungere il supporto per la sostituzione del <inheritdoc/>tag nei file di documentazione XML stessi. Disponibile su www.inheritdoc.io (versione gratuita disponibile).


0

Bene, c'è una sorta di soluzione nativa che ho trovato per .NET Core 2.2

L'idea è usare <include> tag.

Puoi aggiungere il <GenerateDocumentationFile>true</GenerateDocumentationFile>tuo.csproj file di a.

Potresti avere un'interfaccia:

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

E qualcosa che eredita da esso:

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, fa un po 'paura, ma aggiunge gli elementi attesi al file YourNamespace.xml.

Se si costruisce Debugla configurazione, è possibile scambiare Releaseper l'attributo del tag.Debugfileinclude

Per trovare un corretto member's namedi riferimento generato basta aprire Documentation.xmlil file.

Presumo inoltre che questo approccio richieda la creazione di un progetto o di una soluzione almeno due volte (la prima volta per creare un file XML iniziale e la seconda per copiare elementi da esso a se stesso).

Il lato positivo è che Visual Studio convalida gli elementi copiati, quindi è molto più facile mantenere la documentazione e il codice sincronizzati con l'interfaccia / classe base, ecc. (Ad esempio nomi di argomenti, nomi di parametri di tipo, ecc.).

Nel mio progetto, sono finito con entrambi <inheritdoc/>(per DocFX) e <include/>(per la pubblicazione di pacchetti NuGet e per la convalida in 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();
Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.