Visual Studio Hacks [Electronic resources]

Andrew Lockhart

نسخه متنی -صفحه : 172/ 103
نمايش فراداده

Hack 68. Master C# XML Comments

Comment your code with a sprinkling of XML, and give IntelliSense and documentation tools plenty of grist for their mills.

XML comments are a compelling addition to any project. Using XML comments, you can document all of your public classes, methods, and enumerations while you program. The basics of XML comments are very simpleprecede your comments with ///, and Visual Studio will add a basic summary and an element for each of the parameters on your method. You can then enter the summary and parameter descriptions. But there is much more to XML comments; there are 20 different tags that can be used in XML comments. In this hack, you are going to learn how to use all of these tags to create better documentation.

To insert XML comments, simply type /// on a line preceding a class, interface, method, field, or property declaration. As soon as you type these characters, IntelliSense will give you a skeletal XML comment with an empty <summary> element:

/// <summary>
/// 
/// </summary>
public void Foo( )

Technically you can put anything you want in your XML comments. You can make up an XML element and use it without having to do any sort of configuration or work. The only problem is that most tools won't recognize your custom element. By default, documentation generation tools like NDoc [Hack #71] recognize only the standard XML comments. Visual Studio also uses the standard tags to populate IntelliSense comments for your types.

8.2.1. Primary Tags

The first group of comment tags are the primary tags. The primary tags are the tags that you can use independently of other tags. Another set, called the secondary tags, can be used inside of the primary tags to mark up text. The primary tags are used by documentation generation tools to create documentation. When a tool sees a <summary> tag, it knows that the text inside that tag is used to summarize whatever the XML comments are describing.

8.2.1.1 <remarks>

The <remarks> tag is used to describe a type. You might not know this because when you insert XML comments in Visual Studio, it inserts a <summary> tag rather than a <remarks> tag. The difference is not huge, but the C# documentation recommends using <remarks>, so it is a good idea to do so. Here is an example of the <remarks> tag describing a class:

/// <remarks>
/// Vechicle is used as a base class for other specific classes.
/// It includes virtual methods like Start and TurnOff
/// </remarks>
public class Vehicle

The <remarks> tag should explain the purpose of your type.

8.2.1.2 <summary>

Since it appears by default, the <summary> tag is probably the most familiar of these tags. It should be used to document the general purpose of all public methods, properties, and fields of a type. Here is an example of the <summary> tag being used to describe the purpose of a method:

/// <summary>
/// Classes that inherit from Vehicle should override
/// this method and implement a function that starts
/// the vehicle.
/// </summary>
public virtual void Start( )

8.2.1.3 <value>

Similar to the <summary> and <remarks> tags, the <value> tag describes the value of a property. The usage is similar to the other tags:

/// <value>
/// This property contains the number of doors that this vehicle has.
/// </value>
public int NumOfDoors

Each of your properties should include a <value> tag describing what exactly the property represents.

8.2.1.4 <param>

The <param> tag is used to document each of a method's parameters. This is one of the most useful comments because it is sometimes hard to discern the purpose of a parameter just from its name. You might have a parameter called startDate, but what is this the start date of? The <param> tag can be used to answer those questions. Here is an example of using the <param> tag to document the parameters of a method:

/// <summary>
/// This method sets the owner of this vehicle 
/// in the database table VehicleOwner
/// </summary>
/// <param name="ownerID">The userID of the owner</param>
/// <param name="startDate">
/// The date that this user took ownership of this vehicle
/// </param>
public void SetOwner(int ownerID, DateTime startDate)

Notice that the <param> tag includes an attribute called name that is used to specify which parameter this comment is describing. You should be sure and specify the exact name of the parameter, as it is case sensitive. The <param> tag is especially valuable because it is used in the IntelliSense pop up for parameters. Below the normal IntelliSense information, you will see your comment displayed.

8.2.1.5 <returns>

The <returns> tag is used to define the return type of a method. From the signature of the method, you know what type it returns, so simply stating "integer" is pointless. Instead, you should explain what the integer represents. Here is an example of using the <returns> tag to document the return value of a method:

/// <summary>
/// This method retrieves the owner of this vehicle
/// </summary>
/// <returns>The userID of the vehicle's owner</returns>
public int GetOwnerID( )
{
return new int( );
}

8.2.1.6 <exception>

The <exception> tag is used to specify the exceptions a type can throw. This tag uses an attribute called cref. The cref attribute is used to reference another type and is covered in more detail in Section 8.2.2 of this hack. Using the <exception> tag, you should document any specific exceptions that your method might throw with the cref attribute and then explain when the exception could be thrown. Here is an example of using the <exception> tag:

/// <summary>
/// This method retrieves the owner of this vehicle
/// </summary>
/// <returns>The userID of the vehicle's owner</returns>
/// <exception cref="IDNotFoundException">
/// If an owner is not found for this vehicle 
/// this exception will be thrown
/// </exception>
public int GetOwnerID( )

Knowing what exceptions a method might throw is very important to developing high-quality applications. Since .NET does not allow you to specify the exceptions a method might throw in the method signature, this is the next best option.

8.2.1.7 <example>

The <example> tag can be used to provide an example of how to use your method, property, or field. Examples are a key part of high-quality documentation, and nothing can better show developers how to work with your types. Using the <example> tag in conjunction with the <code> tag (one of the secondary tags), you can provide code examples directly in your code. Here is an example of using an <example> tag:

/// <summary>
/// This method sets the owner of this vehicle 
/// in the database table VehicleOwner
/// </summary>
/// <param name="ownerID">The userID of the owner</param>
/// <param name="startDate">
/// The date that this user took ownership of this vehicle
/// </param>
/// <example>
/// <code>
///    // Get the user
///    User user = User.Get(userID);
///    // Call the setOwner method using his ID and the current date
///    SetOwner(user.ID, DateTime.Now);        
/// </code>
/// </example>
public void SetOwner(int ownerID, DateTime startDate)

This example shows the user how to get the userID and then call the SetOwner method. The <example> tag should be used whenever the use of your type is not straightforward. To reinforce the importance of using this tag, imagine trying to use the MSDN documentation without examples.

8.2.1.8 <permission>

The <permission> tag allows you to specify who is allowed to access your type. The <permission> tag can also include the cref attribute and almost always points to System.Security.PermissionSet. Here is an example of using the <permission> tag to describe the permission setting for a method:

/// <summary>
/// Classes that inherit from Vehicle should override
/// this method and implement a function that starts
/// the vehicle.
/// </summary>
/// <permission cref="System.Security.PermissionSet">
/// Public Access
/// </permission>
public virtual void Start( )

In this example, I simply state that the Start() method is available for public use.

8.2.1.9 <seealso>

The <seealso> tag can be used to reference other classes or documents that might be of interest to the person reading the documentation. You can include any number of <seealso> tags that point to other types or type members. Here is an example of the <seealso> tag:

/// <summary>
/// This method retrieves the owner of this vehicle
/// </summary>
/// <returns>The userID of the vehicle's owner</returns>
/// <seealso cref="SetOwner"/>
public int GetOwnerID( )

Using the <seealso> tag, you can reference other types, methods, properties, or fields that might be of interest to the user.

8.2.1.10 <include>

The <include> tag is different then the other primary tags because it is used to include outside XML comments, as opposed to documenting anything. The <include> tag can be useful if the XML comments in your source files are becoming increasingly large and unwieldy. To use this tag, you will need to specify the name of the file as well as the XPath expression that should be used to get to your comments. The best way to handle this is to create a file that reproduces the file generated by Visual Studioyou can even let Visual Studio create this file for you and then replace your comments with <include> statements. Here is an example of an <include> statement that would use the generated file (see the "Creating the XML File" section of this hack) for this class:

/// <include file='XMLLib.xml'
/// path='doc/members/member[@name="M:XMLLib.Vehicle.Start"]/*'/>
public virtual void Start( )

When Visual Studio compiles your code, it will use the file and the XPath expression defined in the <include> tag to retrieve the comments for this method and include them in the final XML document.

8.2.2. Secondary Tags

Secondary tags can be used inside of the primary tags. These tags are used to mark up and format the text that is included in the primary tags. In the last section, you saw one of these tags, <code>, but there are 11 secondary tags in all.

8.2.2.1 <c> and <code>

The <c> and <code> tags are both used to define when a piece of text is code. The only difference between the two is that <c> can be used to mark something as inline code in another sentence, whereas <code> is used to set an entire block of text as code. To put it simply, <code> includes line breaks and <c> does not. Here is an example of using <c> when creating the summary of a method:

/// <summary>
/// This method closes a door of the vehicle. 
/// To close the first door you can simply call <c>CloseDoor(1)</c>
/// </summary>
/// <param name="door">The number of door</param>
public void CloseDoor(int doo

If you wanted to provide a complete example, using the <code> tag would be appropriate:

/// <summary>
/// This method closes a door of the vehicle. 
/// </summary>
/// <param name="door">The number of door</param>
/// <example>
/// <code>
/// //Call the CloseDoor method for the first door
/// CloseDoor(1);
/// </code>
/// </example>
public void CloseDoor(int door)

Both of these tags should be used whenever you include code in your comments.

8.2.2.2 <para>

The <para> tag is used to designate a paragraph in your comments. If your comments are lengthy, it is usually a good idea to break them into paragraphs to facilitate easier reading. Here is an example of using the <para> tag:

/// <remarks>
/// Vechicle is used as a base class for other specific classes.
/// It includes virtual methods like Start and TurnOff
/// <para>Inheriting from the Vehicle class will 
/// let you take advantage of the mapping classes 
/// already created for the vehicle type</para>
/// </remarks>
public class Vehicle

8.2.2.3 <pararef>

The <pararef> tag can be used to make a reference to a parameter. When describing a method, you will frequently refer to a parameter of the method. Using this tag, the documentation generation tool can determine which parameter you are referring to and create a link between the two in your documentation. Here is an example of using the <pararef> tag:

/// <summary>
/// This method closes the door specified in <pararef name="door" />
/// </summary>
/// <param name="door">The number of door</param>
public void CloseDoor(int door)

Note when specifying the parameter that it is case sensitive.

8.2.2.4 <see>

The <see> tag can be used much like the <seealso> tag except that you use <see> in the context of another tag. You might want to list some of the methods a class includes and use the <see> tag to refer to those methods:

/// <remarks>
/// Vechicle is used as a base class for other specific classes.
/// It includes virtual methods like <see cref="Start">Start</see> 
/// and <see cref="TurnOff">TurnOff</see>
/// </remarks>
public class Vehicle

8.2.2.5 List tags

The last type of tags is the list tags. These tags are used to create lists inside your comments. The <list> tag is used to create a list and include an attribute called type. This attribute defines what kind of list you are creating; this value can be set to bullet, number, or table. The <listheader> tag is then used to define the header for your list. It can include the <term> and <description> tags, which I'll discuss in just a moment. After the <listheader> tag, your <list> tag can contain any number of <item> tags. Each <item> tag represents an item in your list and can include <term> and <description> tags. Each item should always include a <description> tag, but needs to include a <term> tag only if you are creating a definition list. (You don't have to set any properties to create a definition list; just using <terms> will tell the document generation tool that you are creating a definition list.)

Here is an example of a nondefinition list:

/// <remarks>
/// Vechicle is used as a base class for other specific classes.
/// It includes the following virtual methods:
/// <list>
///   <listheader><description>Methods</description></listheader>
///   <item><description>Start</description></item>
///   <item><description>TurnOff</description></item>
///   <item><description>CloseDoor</description></item>
/// </list>
/// </remarks>
public class Vehicle

Here is an example of a definition list:

/// <summary>
/// Turns the vehicle in a specific direction
/// </summary>
/// <param name="Direction">The Direction to turn.
/// <list>
///   <listheader>
///     <term>Number</term><description>Direction</description>
///   </listheader>
///   <item>
///     <term>1</term><description>North</description>
///   </item>
///   <item>
///     <term>2</term><description>South</description>
///   </item>
///   <item>
///     <term>3</term><description>East</description>
///   </item>
///   <item>
///     <term>4</term><description>West</description>
///   </item>
/// </list>
/// </param>
public void Turn(int Direction)

Both types of lists can be very valuable in commenting your source code.

8.2.2.6 Custom tags

I mentioned earlier that you can create your own custom tags to be used in the XML comments. Here is an example of custom tags being used:

/// <summary>
/// This method retrieves the owner of this vehicle
/// </summary>
/// <returns>The userID of the vehicle's owner</returns>
/// <database>
///   <sproc>usp_GetOwnerIDByVehicleID</sproc>
///   <params>
///     <param>VehicleID</param>
///   </params>
/// </database>
public int GetOwnerID( )

But remember that you would then need to write something to make use of these custom tags (or customize an existing tool). Although this is something that I won't be covering in this book, if you are skilled in XSLT, it is not that hard.

8.2.3. Creating the XML File

After marking up your code files with XML, the next step is to have Visual Studio create an XML file including all of these comments. This is easily done: right-click on your project and then click on Properties. From the property page, select the Configuration Properties folder and then the Build itemthis is shown in Figure 8-1.

Figure 8-1. XML documentation file creation

To enable the XML documentation file creation, you simply need to enter the name of an XML file in the XML Documentation File property setting. In Figure 8-1, I have entered the name XmlLib.xml. When the project is built, Visual Studio will collect all of the XML comments and save them into a single file named XmlLib.xml in the output directory of your project.

You can then use this .xml file to create any different type of documentation [Hack #71] .