Наследование комментариев для C # (на самом деле любой язык)

95

Допустим, у меня есть этот интерфейс

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

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

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

И этот класс

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

Есть ли способ или есть инструмент, который позволяет мне автоматически добавлять комментарии каждого члена в базовый класс или интерфейс?

Потому что я ненавижу переписывать одни и те же комментарии для каждого производного подкласса!

прыгунчик
источник
14
Я не только ненавижу это, но еще и трудно синхронизировать их.
Оливье Жако-Декомб,

Ответы:

17

GhostDoc делает именно это. Для методов, которые не наследуются, он пытается создать описание на основе имени.

FlingThing() становится "Flings the Thing"

Джеймс Карран
источник
2
GhostDoc потрясающий, одна из тех вещей, которые я не знал, что мне нужно, но теперь не могу обойтись без: o)
Николай Данте
184
Автоматически создаваемые документы мне кажутся очень плохой идеей. Они не добавляют никакой полезной информации, а только без надобности взрывают код. Если инструмент может понять, что делает метод, по его имени, то человек также может понять, и никакой документации не требуется.
Lensflare 08
8
@Lensflare Это правда. Однажды мне пришлось использовать фреймворк, в котором были только такие сгенерированные комментарии, которые не добавляли никакой информации к методу / классу. Вместо «Этот метод делает то и то» комментарии вроде «Это метод XY класса Z». xD Кроме того, вы не могли просматривать код, так что все прошло методом проб и ошибок. Больше никогда! :-)
itmuckel
15
@Lensflare Хотя я на 100% согласен с вами в том, что касается использования AGD как такового , я должен отметить, что AGD не предназначены для использования в качестве подобных волшебных кнопок «сделать все». Вместо этого они предназначены для использования в качестве генераторов шаблонов, чтобы уменьшить количество шаблонной повторяющейся документации, которую вы должны написать самостоятельно, чтобы вы могли сосредоточиться на важных вещах. --- Например, он может генерировать <summary>, <param>, <returns>, <throws>, etc...секции для вас. Много раз с достаточно хорошими результатами; в других случаях требуется исправление или расширение, но все же сокращение общих усилий.
XenoRo
5
люди, документация не для разработчиков, а для архитекторов, так что их задницы все прикрыты: «Эй, мы можем прочитать документацию по коду вашего проекта? Конечно, вот она».
Trident D'Gao
157

Вы всегда можете использовать <inheritdoc />тег:

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

Используя crefатрибут, вы даже можете ссылаться на совершенно другой член в совершенно другом классе или пространстве имен!

public class Foo
{
    /// <inheritdoc cref="System.String.IndexOf" />
    public void Bar() { ... } // this method will now have the documentation of System.String.IndexOf
}
Вадим
источник
8
Я не знал, что <inheritdoc /> вообще существует ... Но, насколько я понимаю, комментарий для этого метода не отображается с intellisense.
gerleim 07
12
@gerleim Посмотрите ответ Джеффа Хитона годом ранее и комментарий под ним. У Sandcastle есть <inheritdoc />, а не C #.
rbwhitaker
4
Я вижу комментарии из интерфейса в intellisense с помощью inheritdoc, а также, если в производном классе вообще нет документации с кодом. Но это могло быть из-за того, что я стал резче.
Тим Абелл
9
Resharper 2017.2 улучшил поддержку inheritdoc jetbrains.com/resharper/whatsnew
Dav Evans
4
Visual Studio Enterprise 2017 (версия 15.9.3) не отображает унаследованные комментарии.
herzbube
26

Используйте, /// <inheritdoc/>если хотите наследование. Избегайте GhostDoc или чего-то подобного.

Согласен, раздражает, что комментарии не передаются по наследству. Было бы довольно просто создать надстройку, если бы у кого-то было время (я бы хотел).

Тем не менее, в нашей базе кода мы помещаем XML-комментарии только к интерфейсам и добавляем дополнительные комментарии реализации к классу. Это работает для нас, поскольку наши классы являются частными / внутренними и только интерфейс является общедоступным. Каждый раз, когда мы используем объекты через интерфейсы, у нас есть полные комментарии, отображаемые в intellisence.

GhostDoc - хорошее начало, он упростил процесс написания комментариев. Особенно полезно поддерживать комментарии в актуальном состоянии, когда вы добавляете / удаляете параметры, повторно запускаете GhostDoc, и он обновляет описание.

Деннис
источник
Я сбит с толку - вы сказали избегать GhostDoc, но в конце вы, похоже, одобрили GhostDoc, помогающий упростить задачу. Вы можете пояснить, что имеете в виду?
Майк Мариновски,
Спасибо @MikeMarynowski. Это старый совет. Я думаю, что в то время я хотел сказать, что GhostDoc, как и любой другой генератор, будет добавлять комментарии, но с почти бесполезными деталями, например <param name="origin">The origin.</param>. Смотрите, как ghostdoc говорит самые ужасные вещи для большего количества примеров. Visual Studio теперь имеет гораздо лучший линтинг и генераторы для xmldocs, чтобы вы знали, когда параметры + документы не совпадают, поэтому GhostDoc (или другие инструменты) больше не нужны.
Деннис
15

Это есть в Java, и я постоянно им пользуюсь. Просто делать:

/**
 * {@inheritDoc}
 */

И инструмент Javadoc это понимает.

В C # есть аналогичный маркер:

<inheritDoc/>

Вы можете прочитать больше здесь:

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

ДжеффХитон
источник
37
В C # нет <inheritdoc/>маркера: он есть в Sandcastle . shfb.codeplex.com
Эрик Данд 07
8
Существует запрос голосовой функции пользователя на добавление <inheritdoc /> в C #. Проголосуйте и проголосуйте на visualstudio.uservoice.com/forums/121579-visual-studio/…
deadlydog
1
Ни C #, ни Java (или любой другой язык программирования) не имеют элементов «XML-документа». Это комментарии . Составители ничего о них не знают. Все они строго используются сторонними генераторами документации, будь то javadoc, замок из песка или что-то еще.
Джеймс Карран
4
Когда указывается Java или C #, это ОБЫЧНО означает сообщество связанных инструментов. Ни Java, ни C # не обладают большими возможностями в самом буквальном смысле. Было бы академическим аргументом утверждать, что Java или C # не имеют возможности подключаться к базе данных, потому что это делает библиотека времени выполнения.
JeffHeaton
2
Visual Studio версии 16.4.0 и новее предоставляет intellisense для <inheritDoc />! docs.microsoft.com/en-us/visualstudio/releases/2019/…
ashbygeek
11

Я бы сказал, чтобы напрямую использовать

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

А также

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

Вы должны поместить эти комментарии только в предыдущую строку вашего класса / метода

Это позволит получить информацию о ваших комментариях, например, из интерфейса, который вы задокументировали, например:

    /// <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);
Гэтсби
источник
Спасибо за совет! Этот подход более явный и решает проблему наследования описания класса от класса объекта (даже при реализации интерфейса).
Денис Бабарыкин
8

Resharper имеет возможность копировать комментарии из базового класса или интерфейса.

Свик
источник
1
Ой? Как? Я использую ReSharper и никогда не видел эту опцию при реализации или наследовании интерфейса ... Где это и как вы используете эту опцию?
Jazimov
2
@Jazimov При нажатии Alt + Enter метод переопределения появляется опция «Копировать документацию из базы».
svick
8

Другой способ - использовать <see /> тег документации XML. Это требует дополнительных усилий, но работает из коробки ...

Вот некоторые примеры:

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

Обновить:

Теперь я предпочитаю использовать то, /// <inheritdoc/>что сейчас поддерживается ReSharper.

Матиас Роттер
источник
1

В итоге я создал инструмент для пост-обработки файлов XML-документации, чтобы добавить поддержку замены <inheritdoc/>тега в самих файлах XML-документации. Доступно на www.inheritdoc.io (доступна бесплатная версия).

К. Джонсон
источник
0

Что ж, есть родное решение, которое я нашел для .NET Core 2.2.

Идея в том, чтобы использовать <include>тег.

Можете добавить <GenerateDocumentationFile>true</GenerateDocumentationFile> свой .csprojфайл.

У вас может быть интерфейс:

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

И кое-что, что от него унаследовано:

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.");
    }
}

Хорошо, это немного страшно, но добавляет ожидаемые элементы в YourNamespace.xml .

Если построить Debugконфигурацию, вы можете поменять местами Releaseдля Debugвfile атрибутеinclude тега.

Для того, чтобы найти правильный member«S , nameчтобы ссылаться только на открытом генерироватьсяDocumentation.xml файл.

Я также предполагаю, что этот подход требует, чтобы проект или решение создавалось как минимум дважды (первый раз для создания исходного XML-файла, а второй раз для копирования элементов из него в себя).

Яркая сторона заключается в том, что Visual Studio проверяет скопированные элементы, поэтому намного проще синхронизировать документацию и код с интерфейсом / базовым классом и т. Д. (Например, имена аргументов, имена параметров типа и т. Д.).

В моем проекте у меня были оба <inheritdoc/>варианта (для DocFX) и <include/>(для публикации пакетов NuGet и для проверки в 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();
Конард
источник