Is there a way to use <inheritdoc /> within a <list>? - c#

I'm using XML tags to document my program so I can see descriptions when I hover over my classes, methods, and such. I want to display a list on one of my classes like so:
/// <remarks>
/// <b>List of methods below</b>
/// <list type="table">
/// <listheader>
/// <term>
/// <see cref="MyMethod()"/>
/// </term>
/// <description>
/// <inheritdoc cref="MyMethod()"/>
/// </description>
/// </listheader>
/// </list>
/// </remarks>
public class MyClass
{
/// <summary>
/// Description of MyMethod()
/// </summary>
public void MyMethod()
{
// Do something
}
}
The problem is that <inheritdoc /> is not loading anything in the preview. However, When I move <inheritdoc /> outside of the <list>, with the exact same formatting, it displays perfectly. Is there any way to reference the description of MyMethod() within the list?

<inheritdoc> by default includes all members in the target XML comments. If you need the <summary> you need to select it using the path attribute:
<inheritdoc cref="MyMethod" path='//summary/text()'/>
It should render something like this:

Related

Adding an XML Documentation Comment file for a school project in Visual Code (C#)

I have made a school project that my teacher will check later on.
I am trying to add some Documentation Comments in Visual Studio Code with the help of a plugin that allows me to write /// which makes the xml code automatically.
I have read from the Microsoft Docs about XML Documentation that you can make a seperate XML file rather than clutter the code with comments but i have been having a hard time getting it to work.
Here is an example:
///<include file='docs.xml' path='docs/members[#name="program"]/Select/*'/>
public static bool Select (ConsoleKey input) {
ConsoleKeyInfo key = Console.ReadKey (true);
if (key.Key == input) {
return true;
}
return false;
}
This is what the doc.xml file has about this method:
<doc>
<members name="program">
<Select>
<summary>
Summarizes a way to detect <paramref name ="input"/>.
</summary>
<returns>
true when <paramref name = "input"/> is detected.
</returns>
<param name="input"> Checks what key it should detect.</param>
<example>
<code>
string outputToConsole = "Hello World!";
void Main () {
if (Selecting.Select (ConsoleKey.Spacebar)) {
Console.WriteLine (outputToConsole);
//Prints "Hello World" when key "Spacebar" is pressed!
}
}
</code>
</example>
</Select>
It currently does not work (It does not show a description on the method at all) and i have been racking my head over this.
The documentation says (emphasis mine):
This is an alternative to placing documentation comments directly in your source code file. By putting the documentation in a separate file, you can apply source control to the documentation separately from the source code. One person can have the source code file checked out and someone else can have the documentation file checked out.
I do understand the motivation behind this, but if you decide to use a separate file you can no longer use Visual Studio autocomplete/intellisense to generate the XML elements for you, and you'll need to learn the schema/syntax of the XML documentation file.
Also, as the assembly gets bigger, so will the XML file. In the real world this file could have 1000s of lines of code. From a maintenance and source control perspective, I'd rather have the documentation in the c# source files. I honestly think it's not worth the trouble.
Anyway, if you still want to use the external files there are a few tricks you can use.
Consider a class library named FileDemo. Righ-click the project > Properties > Build and then tick the checkbox XML Documentation File:
This will generate the XML documentation file on build:
And now the funny part. As I mentioned before, the XML documentation file has a particular syntax you'll need to learn. The best way to do it is to add some XML documentation to existing classes, methods etc and check the generated XML. For example, considering the following namespaces and classes:
namespace FileDemo
namespace FileDemo
{
/// <summary>
/// This is a class
/// </summary>
public class Class1
{
/// <summary>
/// Does nothing
/// </summary>
/// <param name="text">Just some text</param>
public void DoNothing(string text)
{
}
}
/// <summary>
/// This is another class
/// </summary>
public class Class2
{
/// <summary>
/// Bla bla
/// </summary>
/// <param name="text">Just some text</param>
public void DoSomething(string text)
{
}
}
}
namespace FileDemo.AnotherNamespace
namespace FileDemo.AnotherNamespace
{
/// <summary>
/// Yet another class
/// </summary>
public class Class3
{
/// <summary>
/// Gets or sets something
/// </summary>
public string Foo { get; set; }
/// <summary>
/// Creates a new instance of <see cref="Class3"/>
/// </summary>
public Class3()
{
}
/// <summary>
/// This method is supposed to calculate something
/// </summary>
/// <param name="firstValue">First value</param>
/// <param name="secondValue">Second value</param>
/// <returns>The result of the calculation</returns>
public int Calculate(int firstValue, int secondValue)
{
return 1;
}
}
}
After building the project, the generated documentation file is the following:
<?xml version="1.0"?>
<doc>
<assembly>
<name>FileDemo</name>
</assembly>
<members>
<member name="T:FileDemo.AnotherNamespace.Class3">
<summary>
Yet another class
</summary>
</member>
<member name="P:FileDemo.AnotherNamespace.Class3.Foo">
<summary>
Gets or sets something
</summary>
</member>
<member name="M:FileDemo.AnotherNamespace.Class3.#ctor">
<summary>
Creates a new instance of <see cref="T:FileDemo.AnotherNamespace.Class3"/>
</summary>
</member>
<member name="M:FileDemo.AnotherNamespace.Class3.Calculate(System.Int32,System.Int32)">
<summary>
This method is supposed to calculate something
</summary>
<param name="firstValue">First value</param>
<param name="secondValue">Second value</param>
<returns>The result of the calculation</returns>
</member>
<member name="T:FileDemo.Class1">
<summary>
This is a class
</summary>
</member>
<member name="M:FileDemo.Class1.DoNothing(System.String)">
<summary>
Does nothing
</summary>
<param name="text">Just some text</param>
</member>
<member name="T:FileDemo.Class2">
<summary>
This is another class
</summary>
</member>
<member name="M:FileDemo.Class2.DoSomething(System.String)">
<summary>
Bla bla
</summary>
<param name="text">Just some text</param>
</member>
</members>
</doc>
As you can see, there is a particular schema/syntax that you need to learn for each element you're trying to document (classes, methods, properties, constructors, parameters, return types, etc).

inheritdoc specific exception using cref

How to use <inheritdoc/> to inherit specific exception from another method. Is it possible to do something like this:
/// <summary>
/// Summary
/// </summary>
/// <inheritdoc cref="Method2(int)" select="exception[#cref='CustomException']" />
public int Method1()
{
return Method2(1);
}
/// <summary>
/// Summary...
/// </summary>
/// <exception cref="ArgumentException">
/// ArgumentException...
/// </exception>
/// <exception cref="CustomException">
/// CustomException...
/// </exception>
public int Method2(int count)
{
// do something
}
When I build documentation and open it, there is no exception for Method1. Currently, my workaround is to add id="CustomException" to Method2 and use <inheritdoc cref="Method2(int)" select="exception[#id='CustomException']" />

<typeparamref> to a parameter of another class in C# XML doc

Is there a way to refer to the generic parameter of another class? I know I can do this with the current class using <typeparamref>.
One example would be when writing the documentation of an async methods. These return Task and people would commonly need to refer to TResult. Look at the "Return Value" on this page, for instance. They used <paramref> which obviously didn't do the job.
/// <returns>
/// A task that represents the asynchronous create operation.
/// The value of the <paramref name="TResult"/> parameter contains the number of documents created.
/// </returns>
public static async Task<int> CreateDocumentsAsync(string filename)
What shall I use instead of <paramref>?
I don't quite understand your question, so I'll post a couple of examples that may help you in regards to generics with the XML documentation.
/// <summary>
///
/// </summary>
/// <typeparam name="T"></typeparam>
/// <param name="obj"></param>
private void IDoSomething<T>(T obj)
{
}
/// <summary>
/// See type <see cref="T:My.Namespace.MyObject"/>
/// </summary>
private MyObject MyObj;
public class MyObject
{
}
I do not think that is possible (and the example with System.IO.Stream.ReadAsync seems to be an example of an invalid reference, see my comment to the question above).
The rest of this post is not an answer to your question but a suggestion for a more correct documentation:
In your concrete example, you could refer to the Result property inside Task<> instead of the impossible reference to the type parameter TResult itself. That is:
/// <returns>
/// The value of the <see cref="Task{_}.Result" /> property contains ...
/// </returns>
public static async Task<int> CreateDocumentsAsync(string filename)
If you do not like the _ hack above, you can do:
/// <returns>
/// The value of the <see cref="Task{Int32}.Result" /> property contains ...
/// </returns>
public static async Task<int> CreateDocumentsAsync(string filename)
Of course, you can refer to int with <see cref="Int32" />.

XML Comments - How do you reference a dictionary indexer properly?

As the name states, I have no idea how to reference a dictionary indexer. Any help here? :)
FYI, I've tried:
<see cref="Item"/>
<see cref="Item(Int32)"/> //Highly doubted this would work.
<see cref="Item(TKey)"/>
<see cref="Item[TKey]"/>
You can use the full property syntax to reference indexers:
namespace ConsoleApplication1
{
/// <summary>
/// See indexer <see cref="P:ConsoleApplication1.MyDictionary`2.Item(`0)"/>
/// </summary>
/// <typeparam name="TKey"></typeparam>
/// <typeparam name="TValue"></typeparam>
public class MyDictionary<TKey, TValue>
{
/// <summary>
/// Indexer
/// </summary>
/// <param name="key"></param>
/// <returns></returns>
public TValue this[TKey key]
{
get { return default(TValue); }
set { }
}
}
}
You can check that the property was resolved properly by inspecting the generated XML file:
<doc>
<assembly>
<name>ConsoleApplication1</name>
</assembly>
<members>
<member name="T:ConsoleApplication1.MyDictionary`2">
<summary>
See <see cref="P:ConsoleApplication1.MyDictionary`2.Item(`0)"/>
</summary>
<typeparam name="TKey"></typeparam>
<typeparam name="TValue"></typeparam>
</member>
<member name="P:ConsoleApplication1.MyDictionary`2.Item(`0)">
<summary>
Indexer
</summary>
<param name="key"></param>
<returns></returns>
</member>
</members>
</doc>
Notice how the first P: matches the second one.
Finally, make sure it's working with Intellisense:
Update by Original Poster (myermian):
I did a little bit of digging and have discovered that the shortform of an indexer property is just "this". Ex: <see cref="this"/>
Try <see cref="P:Item(System.Int32)" /> (the name is Item, not Items)

How do I reference a C# keyword in XML documentation?

<see cref="switch" />, for example, doesn't work - I get the compilation warning: XML comment on ... has syntactically incorrect cref attribute 'switch'
Context for those who are interested...
/// <summary>Provides base functionality for hand-coded abstractions of API method wrappers, mostly those that abstract over
/// parameters that are required to be JSON-encoded.</summary>
public class FacebookArgs : Dictionary<String, Object>
{
/// <summary>Initializes an instance of <see cref="FacebookArgs" />.</summary>
public FacebookArgs() { }
/// <summary>Intializes an instance of <see cref="FacebookArgs" />, that contains elements copied from <paramref name="dictionary "/>.</summary>
/// <param name="dictionary"></param>
public FacebookArgs(IDictionary<String, Object> dictionary)
: base(dictionary) { }
/// <summary>Gets or sets the value associated with the specified key.</summary>
/// <param name="key">The key of the value to get or set.</param>
/// <returns>The value associated with the specified key.</returns>
/// <remarks>This implementation hides the base indexer implementation such that specifying a key that does not exist returns null rather than throwing a <see cref="KeyNotFoundException" />.</remarks>
public new Object this[String key]
{
get
{
Object value;
if (this.TryGetValue(key, out value)) return value;
else return null;
}
set { base[key] = value; }
}
/// <summary>In derived classes, provides specialized serialization logic for specific properties contained in this object.</summary>
/// <param name="key">The key of the property to serialize.</param>
/// <param name="args">A reference to a dictionary of arguments that will be passed directly to a <see cref="FacebookRequest" /> object.</param>
/// <remarks>
/// <para>This method allows specialized serialization logic, such as JSON encoding, to be applied to specific properties.</para>
/// <para>To implement, use a <c>switch</c> (<c>Select</c> in VB.NET) statement to filter based on <paramref name="key" /> and provide the property-specific logic.
/// The resulting value should then be added to <paramref name="args" /> using the same <paramref name="key "/>.
/// </para>
/// <para>Properties that do not require additional processing (strings, integral values, etc) should be ignored.</para>
/// </remarks>
protected virtual void SerializeProperty(String key, ref IDictionary<String, Object> args) { }
/// <summary>Returns a dictionary of key/value pairs suitable to be passed a <see cref="FacebookRequest" /> object.</summary>
/// <returns>A dictionary of key/value pairs suitable to be passed a <see cref="FacebookRequest" /> object.</returns>
/// <remarks>This method calls the <see cref="SerializeProperty" /> for each key in the object, which allows property-specific processing
/// to be done on any property.</remarks>
/// <seealso cref="SerializeProperty" />
public IDictionary<String, Object> GetArgs()
{
IDictionary<String, Object> args = new Dictionary<String, Object>();
foreach (String key in this.Keys)
{
this.SerializeProperty(key, ref args);
if (!args.ContainsKey(key) && this[key] != null)
{
args.Add(key, this[key]);
}
}
return args;
}
}
The tag in question can be found in the <remarks> tag for SerializeProperty. I'm erring on the side of verbose documentation. I also plan on providing some <example>s, I just haven't gotten around to it yet.
cref is meant to refer to another member - a class, a method etc.
What would you expect it to link to in this case? In general, what do you want the overall effect to be?
According to this excellent XML doc guide, the <see> tag has an undocumented attribute langword:
<see langword="switch" />
Would that help you? It might be worth trying it just to see what it does.
If you just want to use a normal hyperlink, use href instead of cref:
<see href="http://msdn.microsoft.com/en-us/library/06tc147t.aspx">switch</see>

Categories

Resources