Ответ 1
GhostDoc делает именно это. Для методов, которые не наследуются, он пытается создать описание из имени.
FlingThing()
становится "Flings the Thing"
Предположим, что у меня есть этот интерфейс
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() { ... }
}
Есть ли способ, или есть инструмент, который может позволить мне автоматически помещать комментарии каждого члена в базовый класс или интерфейс?
Потому что я ненавижу переписывать те же комментарии для каждого производного подкласса!
GhostDoc делает именно это. Для методов, которые не наследуются, он пытается создать описание из имени.
FlingThing()
становится "Flings the Thing"
Вы всегда можете использовать тег <inheritdoc />
.
public class Foo : IFoo
{
/// <inheritdoc />
public void Foo() { ... }
/// <inheritdoc />
public void Bar() { ... }
/// <inheritdoc />
public void Snafu() { ... }
}
Используйте /// <inheritdoc/>
, если вы хотите наследования. Избегайте GhostDoc или чего-либо подобного.
Я согласен, это раздражает, что комментарии не наследуются. Было бы довольно просто создать надстройку, если бы у кого-то было время (хотелось бы).
Тем не менее, в нашей кодовой базе мы размещаем комментарии XML только для интерфейсов и добавляем дополнительные комментарии реализации к классу. Это работает для нас, так как наши классы являются частными/внутренними, и только интерфейс является общедоступным. Каждый раз, когда мы используем объекты через интерфейсы, у нас отображаются полные комментарии в виде интеллигентности.
GhostDoc - хорошее начало, благодаря которому процесс написания комментариев стал проще. Это особенно полезно для поддержания комментариев актуальными, когда вы добавляете/удаляете параметры, перезапускаете GhostDoc, и это обновит описание.
Java имеет это, и я использую его все время. Просто выполните:
/**
* {@inheritDoc}
*/
И инструмент Javadoc показывает это.
С# имеет аналогичный маркер:
<inheritDoc/>
Вы можете прочитать здесь:
http://www.ewoodruff.us/shfbdocs/html/79897974-ffc9-4b84-91a5-e50c66a0221d.htm
У Resharper есть возможность скопировать комментарии из базового класса или интерфейса.
Я бы сказал, чтобы напрямую использовать
/// <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);
Другой способ - использовать тег документации XML <see />
.
Это дополнительное усилие, но оно работает "из коробки"...
Вот несколько примеров:
/// <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.
Я закончил тем, что создал инструмент для пост-обработки файлов документации XML, чтобы добавить поддержку для замены тега <inheritdoc/>
в самих файлах документации XML. Доступно на www.inheritdoc.io (доступна бесплатная версия).
Ну, есть некое родное решение, которое я нашел для .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
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();