Keeping documentation synchronized with the actual implementation is always a challenge. One way of keeping it up-to-date is to write the documentation as part of the source and then extract it into a separate file.
C# supports an XML-based documentation format. It can verify that the XML is well-formed, do some context-based validation, add some information that only a compiler can get consistently correct, and write it out to a separate file.
You can divide C# XML support into two sections: compiler support and documentation convention. In the compiler support section, the tags are specially processed by the compiler for verification of contents or symbol lookup. The remaining tags define the .NET documentation convention and are passed through unchanged by the compiler.
1. Compiler Support Tags
The compiler-support tags are a good example of compiler magic; they’re processed using information that’s known only to the compiler. The following example illustrates how to use the support tags:
// file: employee.cs
using System;
namespace Payroll
{
/// <summary>
/// The Employee class holds data about an employee.
/// This class contains a <see cref=”String”>string</see>
/// </summary>
public class Employee
{
/// <summary>
/// Constructor for an Employee instance. Note that
/// <paramref name=”name”>name2<Iparamref> is a string.
/// <Isummary>
/// <param name=”id”>Employee id number<Iparam>
/// <param name=”name”>Employee Name<Iparam> public Employee(int id, string name)
{
this.id = id;
this.name = name;
}
/// <summary>
/// Parameterless constructor for an employee instance III <Isummary>
/// <remarks>
/// <seealso cref=”Employee(int, string)”>Employee(int, string)<Iseealso>
/// <Iremarks>
public Employee()
{
id = -1;
name = null;
}
int id;
string name;
}
The compiler performs special processing on four of the documentation tags. For the param and paramref tags, it validates that the name referred to inside the tag is the name of a parameter to the function.
For the see and seealso tags, it takes the name passed in the cref attribute and looks it up using the identifier lookup rules so the name can be resolved to a fully qualified name. It then places a code at the front of the name to tell what the name refers to. For example, the following:
<see cref=”String”>
becomes this:
<see cref=”T:System.String”>
String resolved to the System.String class, and T: means that it’s a type.
The seealso tag is handled in a similar manner. For example, the following:
<seealso cref=”Employee(int, string)”>
becomes this:
<seealso cref=”M:Payroll.Employee.#ctor(System.Int32,System.String)”>
The reference was to a constructor method that had an int as the first parameter and a string as the second parameter.
In addition to the preceding translations, the compiler wraps the XML information about each code element in a member tag that specifies the name of the member using the same encoding. This allows a post-processing tool to easily match up members and references to members. The generated XML file from the preceding example is as follows (with a few word wraps):
<?xml version=”1.0″?>
<doc>
<assembly>
<name>employee</name>
</assembly>
<members>
<member name=”T:Payroll.Employee”>
<summary>
The Employee class holds data about an employee.
This class contains a <see cref=”T:System.String”>string</see>
</summary>
</member>
<member name=”M:Payroll.Employee.#ctor(System.Int32,System.String)”>
<summary>
Constructor for an Employee instance. Note that
<paramref name=”name2″>name</paramref> is a string.
</summary>
<param name=”id”>Employee id number</param>
<param name=”name”>Employee Name</param>
</member>
<member name=”M:Payroll.Employee.#ctor”>
<summary>
Parameterless constructor for an employee instance
</summary>
<remarks>
<seealso cref=”M:Payroll.Employee.#ctor(System.Int32,System.String)” >Employee(int, string)</seealso>
</remarks>
</member>
</members>
</doc>
The post-processing on a file can be quite simple; you can add an XSL file that specifies how the XML should be rendered, which leads to the display shown in Figure 38-1 (in a browser that supports XSL).
Note that XML documentation isn’t designed to be a full solution to generating documentation. The final documentation should be generated by a tool that uses reflection to examine a class and combines the information from XML documentation to the information from reflection to produce the final documentation.
2. XML Documentation Tags
The remainder of the XML documentation tags describes the .NET documentation convention. They can be extended, modified, or ignored if necessary for a specific project. Table 38-2 shows the XML elements you can use for documentation.
3. XML Include Files
In a project that has a separate technical-writing team, it may be more convenient to keep the XML text outside the code. To support this, C# provides an include syntax for XML documentation. Instead of having all the documentation before a function, you can use the following include statement:
/// <include file=’Foo.csx’ path=’doc/member[@name=”Foo.Comp”]’ />
This will open the Foo.csx file and look for a <doc> tag. Inside the doc section, it will then look for a <member> tag that has the name Foo .Comp specified as an attribute. In other words, it will look for something like this:
<doc>
<member name=”Foo.Comp”>
<summary>A description of the routine</summary>
<param name=”obj1″>the first object</param>
</member>
</doc>
Once the compiler has identified the matching section from the include file, it proceeds as if the XML were contained in the source file.
Source: Gunnerson Eric, Wienholt Nick (2005), A Programmer’s Introduction to C# 2.0, Apress; 3rd edition.