I’ve been updating one of my GitHub repositories (my Presentation.Core repo.) with some more documentation, using XML documentation comments, and thought I’d write a refresher post for taking your code from no documentation all the way through to being fully documented.
<summary>
So the /// is used for XML documenting comments in C#, for example
/// <summary>
/// A Task/async aware command object.
/// </summary>
public class AsyncCommand : CommandCommon
{
}
In the above, the <summary> element (and it’s corresponding end element) within the /// acts as a summary of our class. This class level summary is displayed in Visual Studio Intellisense when declaring a type of AsyncCommand when we create code such as new AsyncCommand() Intellisense will display the summary for the default constructor (if such documentation exists).
The summary tag is the most important tag for documenting our code using the XML documentation as it’ll acts as the primary source of information for Intellisense and within generated help files.
<remarks>
This is an optional documentation <remarks> element which can be used to expand upon the summary or add supplementary documentation to the summary element. For example
/// <summary>
/// A Task/async aware command object.
/// </summary>
/// <remarks>
/// Automatically handles changes to the built-in, IsBusy flag, so when
/// the command is executing the IsBusy is true and when completed or not
/// executing IsBusy is false.
/// </remarks>
public class AsyncCommand : CommandCommon
{
}
Summary text is displayed by IntelliSense whereas Remarks are shown in the help file output via tools such as Sandcastle.
<returns>
As you might guess, the <returns> element is used on method return values, for example
/// <summary>
/// Implementation of CanExecute which returns a boolean
/// to allow the calling method to determine whether the
/// Execute method can be called
/// </summary>
/// <param name="parameter">An object is ignored in this implementation</param>
/// <returns>True if the command can be executed, otherwise False</returns>
public override bool CanExecute(object parameter)
{
}
<param>
Continuing with the elements available for a method, the param element is used for method arguments, to allow the documentation to list what each parameter is used for.
/// <summary>
/// Implementation of CanExecute which returns a boolean
/// to allow the calling method to determine whether the
/// Execute method can be called
/// </summary>
/// <param name="parameter">An object is ignored in this implementation</param>
/// <returns>True if the command can be executed, otherwise False</returns>
public override bool CanExecute(object parameter)
{
}
<value>
Like a return but used on a property, the <value> element is used along with a summary to describe what the property represents.
<para>
The <para> element is used within summary, remarks or return elements to add paragraph formatting/structure to your documentation.
<exception>
The <exception> element is used (as the name suggests) to list exceptions a method may throw during it’s execution. For example
/// <summary>
/// Constructor take a comparison function which expects two types of T and
/// returns an integer where a value less than 0 indicates the first item is
/// before the second, a value of 0 indicates they're equivalent
/// and a value greater than 0 indicates the first item is after
/// the second item. This constructor also takes a function for the object
/// hash code method.
/// </summary>
/// <param name="objectComparer">
/// A function to compare two items of type T
/// </param>
/// <exception cref="System.NullReferenceException">
/// Thrown when the objectComparer is null
/// </exception>
public ComparerImpl(
Func<T, T, int> objectComparer)
{
_objectComparer =
objectComparer ??
throw new NullReferenceException("Comparer cannot be null");
}
IntelliSense will display the list of exceptions
<see>
The <see> element allows us to reference documentation elsewhere within your code, it accepts a cref argument and within this we need to reference our classname.methodname etc. For example
/// <summary>
/// Sets the property value against the property and raises
/// OnPropertyChanging, OnPropertyChanged etc. as required.
/// <see cref="GetProperty{T}"/>
/// </summary>
protected bool SetProperty<T>(
Func<T> getter,
Func<T, T> setter,
T value,
[CallerMemberName] string propertyName = null)
{
}
Note: In the case of reference another method within the same class we need not declare the class name within the cref, but if referencing another class we should use classname.methodname syntax.
Within IntelliSense and documentation the full method name will be displayed for the see element’s cref.
<seealso>
Usage for <seealso> is as per the see element but generated code will create a see also section and place such references within.
<typeparam>
The <typeparam> element is used to document the generic parameters passed to a class and/or methods, for example
/// <summary>
/// Implements IComparer<T>, IEqualityComparer<T>
/// and IComparer
/// </summary>
/// <typeparam name="T">The type of being compared</typeparam>
public class ComparerImpl<T> :
IComparer<T>, IEqualityComparer<T>, IComparer
{
}
<paramref>
Used within a summary or remarks, the <paramref> is used to refer to a parameter on the method being documented. For example
/// <summary>
/// Gets the current value via a Func via the <paramref name="generateFunc"/>
/// </summary>
/// <typeparam name="T">The property type</typeparam>
/// <param name="generateFunc">The function to create the return value</param>
/// <param name="propertyName">The name of the property</param>
/// <returns>The value of type T</returns>
protected T ReadOnlyProperty<T>(
Func<T> generateFunc,
[CallerMemberName] string propertyName = null)
{
}
In the above, generateFunc is displayed within the IntelliSense summary and highlighted (via an italic font) in generated help files.
<typeparamref>
Like paramref, the <typeparamref> element can be used within summary, remarks etc. to link to a specific generic type, for example
/// <summary>
/// Gets the current property value as type <typeparamref name="T"/>
/// </summary>
protected T GetProperty<T>(
Func<T> getter,
Func<T, T> setter,
[CallerMemberName] string propertyName = null)
{
}
As per paramref generated documentation may highlight the name within a help file and it’s also displayed via IntelliSense within the summary.
<list>
The <list> element allows us to define formatted text in a bullet, name or table format within our summary block, for example
/// <summary>
/// Acts as a base class for view models, can be used
/// with backing fields or delegating getter/setter
/// functionality to another class - useful for situations
/// where the underlying model is used directly
/// <list type="bullet">
/// <item><description>GetProperty</description></item>
/// <item><description>SetProperty</description></item>
/// <item><description>ReadOnlyProperty</description></item>
/// </list>
/// </summary>
public class ViewModelWithModel : ViewModelCommon
{
}
This results in generated documentation showing a bullet list of items, within IntelliSense, this isn’t quite so pretty and results in just the descriptions listed with space delimitation.
<example>
The <example> element allows us to add example code to our documentation, for example
/// <summary>
/// Sets the property value against the property and raises
/// OnPropertyChanging, OnPropertyChanged etc. as required
/// </summary>
/// <example>
/// <code>
/// public string Name
/// {
/// set => SetProperty(value);
/// get => GetProperty();
/// }
/// </code>
/// </example>
protected bool SetProperty<T>(
T value,
[CallerMemberName] string propertyName = null)
{
}
Note: Without the <code> element the example is not formatted as we’d expected. This is results in a generated help file section named examples.
<code>
The <code> element is used within the example element to format code samples. See above.
<c>
The <c> element may be used within a summary or other element and formats the text within it as code.
<permission>
As you probably guessed, we can highlight the permissions expected or required for a method etc. using the <permission> element. For example
/// <summary>
/// Gets the current property value
/// </summary>
/// <permission cref="System.Security.PermissionSet">
/// Unlimited access to this method.
/// </permission>
protected T GetProperty<T>([CallerMemberName] string propertyName = null)
{
}
The above will result in generated documentation with a security section which includes a table of the cref value and the description for the permissions required for the method.
<include>
The <include> element allows us to use documentation from an external XML file.
How do we generate the XML documents?
Once we’ve documented our code using the XML documentation we will need to get Visual Studio to generate the XML files for the documents, basically extracting the comment blocks into these external files.
For each project you wish to generate documentation for (within Visual Studio) select the properties for the project and then the Build tab. In the Output sections check the XML documentation file check box and either allow the default file name or create your own.
References
Documenting your code with XML comments