Dziedziczenie komentarzy dla języka C # (właściwie dowolnego języka)

94

Załóżmy, że mam ten interfejs

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

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

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

I ta klasa

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

Czy jest sposób lub czy istnieje narzędzie, które pozwala mi automatycznie umieszczać komentarze każdego elementu członkowskiego w klasie bazowej lub interfejsie?

Ponieważ nienawidzę ponownego pisania tych samych komentarzy dla każdej pochodnej podklasy!

Jumpinjackie
źródło
14
Nie tylko tego nienawidzę, ale także trudno mi je zsynchronizować.
Olivier Jacot-Descombes

Odpowiedzi:

16

GhostDoc robi dokładnie to. W przypadku metod, które nie są dziedziczone, próbuje utworzyć opis z nazwy.

FlingThing() staje się "Flings the Thing"

James Curran
źródło
2
GhostDoc jest niesamowity, jedna z tych rzeczy, o których nie wiedziałem, że potrzebuję, ale teraz nie mogę się obejść bez: o)
NikolaiDante
182
Dokumenty generowane automatycznie wydają mi się bardzo złym pomysłem. Nie dodają żadnych przydatnych informacji, a jedynie niepotrzebnie wysadzają kod. Jeśli narzędzie może zrozumieć, co robi metoda na podstawie swojej nazwy, to osoba może również to zrozumieć i nie jest potrzebny żaden dokument.
Lensflare
8
@Lensflare To takie prawdziwe. Kiedyś musiałem użyć frameworka, który miał tylko takie wygenerowane komentarze, które nie dodawały żadnych informacji do metody / klasy. Zamiast „Ta metoda robi to i owo”, komentarze brzmiały jak „To jest metoda XY klasy Z”. xD Również nie mogłeś przeglądać kodu, więc przeszedł do prób i błędów. Nigdy więcej! :-)
itmuckel
15
@Lensflare Chociaż 100% zgadzam się z tobą o ile powołując się na AGDs jak to należy wskazać, że AGDs nie są przeznaczone do stosowania jako „zrób to wszystkie” magiczne przyciski tak. Zamiast tego mają być używane jako generatory szablonów, aby zmniejszyć ilość szablonowej, powtarzalnej dokumentacji, którą musisz sam napisać, abyś mógł skupić się na ważnych rzeczach. --- Na przykład, może generować <summary>, <param>, <returns>, <throws>, etc...sekcje dla Ciebie. Wiele razy z wystarczająco dobrymi wynikami; innym razem wymaga poprawek lub rozszerzenia, ale nadal zmniejsza ogólny wysiłek.
XenoRo
5
ludzie, dokumentacja nie jest dla programistów, ale dla architektów, więc ich tyłki są pokryte: „Hej, czy możemy przeczytać dokumentację kodu twojego projektu? Jasne, oto ona”.
Trident D'Gao
154

Zawsze możesz użyć <inheritdoc />tagu:

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

Używając crefatrybutu, możesz nawet odwołać się do zupełnie innego członka w zupełnie innej klasie lub przestrzeni nazw!

public class Foo
{
    /// <inheritdoc cref="System.String.IndexOf" />
    public void Bar() { ... } // this method will now have the documentation of System.String.IndexOf
}
Vadim
źródło
8
Nie wiedziałem, że <inheritdoc /> w ogóle istnieje ... Ale z tego co widzę, komentarz dotyczący tej metody nie pojawia się w przypadku inteligencji.
gerleim
12
@gerleim Spójrz na odpowiedź Jeffa Heatona sprzed roku i komentarz pod nią. Sandcastle ma <inheritdoc />, a nie C #.
rbwhitaker
4
Widzę komentarze z interfejsu w Intellisense z inheritdoc, a także, jeśli w klasie pochodnej nie ma w ogóle dokumentu-kodu. Ale może to być spowodowane tym, że mam odwagę.
Tim Abell
9
Resharper 2017.2 poprawił obsługę inheritdoc jetbrains.com/resharper/whatsnew
Dav Evans
4
Visual Studio Enterprise 2017 (wersja 15.9.3) nie wyświetla odziedziczonych komentarzy.
herzbube
26

Użyj, /// <inheritdoc/>jeśli chcesz dziedziczyć. Unikaj GhostDoc lub czegoś podobnego.

Zgadzam się, że to denerwujące, że komentarze nie są dziedziczone. Byłby to dość prosty dodatek do stworzenia, gdyby ktoś miał czas (żałuję, że nie miał).

To powiedziawszy, w naszej bazie kodu umieszczamy komentarze XML tylko na interfejsach i dodajemy dodatkowe komentarze dotyczące implementacji do klasy. To działa dla nas, ponieważ nasze zajęcia są prywatne / wewnętrzne i tylko interfejs jest publiczny. Za każdym razem, gdy używamy obiektów przez interfejsy, mamy pełne komentarze wyświetlane w inteligencji.

GhostDoc to dobry początek i ułatwił proces pisania komentarzy. Szczególnie przydatne jest utrzymywanie aktualności komentarzy podczas dodawania / usuwania parametrów, ponownego uruchamiania GhostDoc i aktualizowania opisu.

Dennis
źródło
Jestem zdezorientowany - powiedziałeś, że unikasz GhostDoc, ale na końcu najwyraźniej poparłeś GhostDoc, pomagając ci to ułatwić. Czy możesz wyjaśnić, co masz na myśli?
Mike Marynowski
Dzięki @MikeMarynowski. To stara rada. Myślę, że chciałem wtedy powiedzieć, że GhostDoc, jak każdy inny generator, doda komentarze, ale z prawie bezużytecznymi szczegółami, np <param name="origin">The origin.</param>. Zobacz ghostdoc mówi najgorsze rzeczy, aby uzyskać więcej przykładów. Program Visual Studio ma teraz znacznie lepsze lintowanie i generatory dla xmldocs, aby poinformować Cię, gdy parametry + dokumenty nie są wyrównane, więc GhostDoc (lub inne narzędzia) nie są już potrzebne.
Dennis
15

Java to ma i używam go cały czas. Po prostu zrób:

/**
 * {@inheritDoc}
 */

Narzędzie Javadoc rozwiązuje to.

C # ma podobny znacznik:

<inheritDoc/>

Możesz przeczytać więcej tutaj:

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

JeffHeaton
źródło
37
C # nie ma <inheritdoc/>znacznika: Sandcastle go ma. shfb.codeplex.com
Eric Dand
8
Istnieje żądanie funkcji głosowej użytkownika, aby dodać <inheritdoc /> do C #. Głosuj w górę
deadlydog
1
Ani C #, ani Java (ani żaden inny język programowania) nie mają żadnych elementów „XML doc”. To są komentarze . Kompilatorzy nic o nich nie wiedzą. Wszystkie są ściśle używane przez zewnętrzne generatory dokumentacji, czy to javadoc, sandcastle czy cokolwiek.
James Curran
4
Kiedy mowa o Java lub C #, ZWYKLE oznacza społeczność powiązanych narzędzi. Ani Java, ani C # nie mają wielu umiejętności w bardzo dosłownym sensie. Argumentem akademickim byłoby stwierdzenie, że Java lub C # nie mają możliwości połączenia się z bazą danych, ponieważ robi to biblioteka wykonawcza.
JeffHeaton,
2
Program Visual Studio w wersji 16.4.0 i nowsze zapewniają funkcję Intellisense dla <inheritDoc />! docs.microsoft.com/en-us/visualstudio/releases/2019/…
ashbygeek
10

Powiedziałbym, aby bezpośrednio użyć

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

I

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

Musisz umieścić ten komentarz w poprzednim wierszu swojej klasy / metody

Spowoduje to uzyskanie informacji o twoich komentarzach, na przykład z interfejsu, który udokumentowałeś, takiego jak:

    /// <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
źródło
Dzięki za radę! Takie podejście jest bardziej jednoznaczne i rozwiązuje problem dziedziczenia opisu klasy z klasy obiektu (nawet przy implementacji interfejsu).
Denis Babarykin
8

Resharper ma opcję kopiowania komentarzy z klasy bazowej lub interfejsu.

svick
źródło
1
O? W jaki sposób? Używam ReSharper i nigdy nie widziałem tej opcji podczas implementowania lub dziedziczenia interfejsu ... Gdzie to jest i jak używasz tej opcji?
Jazimov
2
@Jazimov Po naciśnięciu Alt + Enter metodę zastępowania, istnieje opcja „Kopiuj dokumentację z bazy”.
svick
8

Innym sposobem jest użycie <see />znacznika dokumentacji XML. To dodatkowy wysiłek, ale działa po wyjęciu z pudełka ...

Oto kilka przykładów:

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

Aktualizacja:

Wolę teraz używać tego, /// <inheritdoc/>który jest teraz obsługiwany przez ReSharper.

Mathias Rotter
źródło
1

Skończyło się na stworzeniu narzędzia do końcowego przetwarzania plików dokumentacji XML, aby dodać obsługę zastępowania <inheritdoc/>znacznika w samych plikach dokumentacji XML. Dostępne na www.inheritdoc.io (dostępna bezpłatna wersja).

K Johnson
źródło
0

Cóż, jest coś w rodzaju natywnego rozwiązania, które znalazłem dla .NET Core 2.2

Chodzi o to, aby użyć <include>tagu.

Możesz dodać <GenerateDocumentationFile>true</GenerateDocumentationFile>swój .csprojplik.

Możesz mieć interfejs:

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

I coś, co po nim dziedziczy:

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, jest to trochę przerażające, ale dodaje oczekiwane elementy do YourNamespace.xml.

Jeśli budować Debugkonfigurację, można zamienić Releasena Debugw fileatrybucieinclude znacznika.

Aby znaleźć poprawne member„s nameodwołać wystarczy otworzyć wygenerowany Documentation.xmlplik.

Zakładam również, że takie podejście wymaga co najmniej dwukrotnego zbudowania projektu lub rozwiązania (za pierwszym razem do utworzenia początkowego pliku XML, a za drugim do skopiowania z niego elementów do siebie).

Jasną stroną jest to, że Visual Studio sprawdza poprawność skopiowanych elementów, więc znacznie łatwiej jest zsynchronizować dokumentację i kod z interfejsem / klasą bazową itp. (Na przykład nazwy argumentów, nazwy parametrów typu itp.).

W moim projekcie skończyło się na obu <inheritdoc/>(dla DocFX) i <include/>(Do publikowania pakietów NuGet i do walidacji w 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
źródło