One of the most common programming rules states that documenting the source code is fundamental. This is the truth, but you have to think about the way source code is commented. Classical comments are useful to explain what code does so that you can easily remember how your code works if you need to reuse it after a long time, or they can help other developers to understand your code. But this is not the only way of documenting code in .NET development. A sophisticated environment such as Visual Studio offers the IntelliSense technology that speeds up the way you write code and shows instructions on how you use objects and members. This is possible because of special kinds of comments that you can add to your code, known as XML comments. Such comments enable you to write the source code documentation, explain objects’ and members’ behavior, and provide descriptions and examples that can be displayed by IntelliSense. But that is not all. Documenting code with XML comments is particularly important if you develop reusable compiled libraries and enables you to automate the process of building compiled documentation files (such as .chm files) in a similar way to the MSDN documentation. In this chapter, you learn to use XML comments to provide simple and complex source code documentation, also learning how to build compiled documentation.
XML comments are not new in Visual Basic 2012; they were first natively introduced with Visual Basic 2005. (In versions prior to 2005, XML comments were possible only via third-party add-ins.) To understand why XML comments are an essential topic, let’s take a look at a method invocation within the code editor. Figure 49.1 shows how IntelliSense appears on an uncommented method.
As you can see from Figure 49.1, IntelliSense will correctly display, but it will just show the method name in a tooltip, without providing information on the method usage. This is because the method was not commented with XML comments. Now take a look at Figure 49.2. It shows how IntelliSense can provide information if the method was commented with XML comments.
The difference is evident. Objects and members decorated with XML comments can provide full explanation on their usage. This works in the code editor when IntelliSense displays with both source files and with compiled executables. As mentioned at the beginning of this chapter, providing XML comments is useful not only for IntelliSense, but also when you investigate objects in the Object Browser or for automating the process of building compiled documentation for your libraries. Because of this, adding XML comments to your code is necessary in most cases, especially if you develop reusable assemblies. In the next sections, you learn practical techniques for commenting the source code and getting the most out of XML comments with Visual Basic.
When Visual Studio builds the project output, it also creates an XML document storing all XML comments. The XML document constitutes the actual code documentation. In Visual Studio 2012, XML comments are enabled by default. Before reading this chapter, ensure that XML comments are enabled in your project. To accomplish this, open My Project; select the Compile tab and, if it’s not checked, check the Generate XML Documentation file box. See Figure 49.3 for details.
Behind the scenes, this requires the Visual Basic compiler to be launched by Visual Studio with the /doc option, which makes the compiler also generate the XML documentation. At this point, you are ready to implement XML comments in your Visual Basic code.
XML comments have a double purpose. The first one is enabling additional help within IntelliSense when you write code. The second one is generating an XML file storing information that can be built into a compiled documentation file, such as the .chm format that also enables navigation between documented items. In this section, you learn to implement XML comments and learn the various tags and why they are important, although in some cases they might not seem to be. Before implementing comments, create a new Console application and implement a Person
class as follows:
Public Class Person
Public Overridable Property FirstName As String
Public Overridable Property LastName As String
Public Overridable Property Age As Integer
Public Overridable Function GetFullName() As String
Dim fn As New Text.StringBuilder
fn.Append(Me.FirstName)
fn.Append(" ")
fn.Append(Me.LastName)
Return fn.ToString
End Function
End Class
The Person
class will be the base for our experiments. You implement an XML comment by typing three apostrophes. The Visual Studio code editor adds a comment skeleton to your code that first looks like the following example:
''' <summary>
'''
''' </summary>
''' <returns></returns>
''' <remarks></remarks>
Public Overridable Function GetFullName() As String
Dim fn As New Text.StringBuilder
fn.Append(Me.FirstName)
fn.Append(" ")
fn.Append(Me.LastName)
Return fn.ToString
End Function
As you can see, these comments have typical XML structure according to the <tag> </tag>
syntax. The summary
XML tag enables describing what an object (or member) does. The description will be also available within IntelliSense. The remarks
tag enables you to provide additional information on what you already specified in the summary, and the information will also be displayed within the Object Browser (but not within IntelliSense). The returns
tag specifies the type returned by the member (being a method or a property); if the member is a method that does not return a value, Visual Studio will not add the returns
tag. For a better understanding, populate comments as follows:
''' <summary>
''' Gets the complete person's name
''' </summary>
''' <returns>String</returns>
''' <remarks>This method returns the complete person's name</remarks>
Public Overridable Function GetFullName() As String
Dim fn As New Text.StringBuilder
fn.Append(Me.FirstName)
fn.Append(" ")
fn.Append(Me.LastName)
Return fn.ToString
End Function
Now go to the Main method in your Console application, and write the following code that instantiates and populates the Person class:
Dim p As New Person With {.FirstName = "Alessandro", .LastName = "Del Sole",
.Age = 35}
Dim fullName As String = p.GetFullName
When typing code, IntelliSense provides information on the GetFullName
method according to the XML comment’s content. This is represented in Figure 49.4.
As you can see, IntelliSense shows the content of the summary
tag, but it does not show the content of the returns
and remarks
tags. This makes sense in that IntelliSense’s tooltips are the fastest way for getting help. If you instead open the Object Browser on the Person
class, you get a result that looks similar to Figure 49.5 (additional information appearing in the window is covered shortly). You obtain the same detailed information if you build a compiled documentation file, as described later in this chapter. The one shown before is the most basic implementation of XML comments. This great Visual Basic feature enables you to define complex documentation over your code, which can be particularly useful due to the integration with the Visual Studio environment.
Scope
XML comments can be applied to both public and private objects and members.
The MSDN documentation says that the Visual Basic compiler can parse any valid XML tag. The MSDN also recommends a series of tags that are specific to the code documentation. Table 49.1 summarizes the recommended tags.
Tags within XML comments are case-sensitive and lowercase. Take note of this to ensure that the Visual Basic compiler correctly recognizes tags.
Note on Complex Documentation
You can appreciate complex documentation generated with XML comments only when building compiled help files. This is because within IntelliSense or in the Object Browser, only a few tags’ contents will be shown. For example, XML comments enable you to build bulleted lists or specify links to other documentation regarding different code. All this cannot be shown in IntelliSense, but it makes a lot of sense in a help file or a help system built on HTML pages. If you are interested in only building documentation for Visual Studio internal usage, you can theoretically limit XML comments to the basic implementations.
Let’s go back to the Person
class and provide an XML comment for the FirstName
property. The XML comment must look like this:
''' <summary>
''' Contains the person's first name
''' </summary>
''' <value>Person's first name</value>
''' <returns>String</returns>
''' <remarks></remarks>
Public Overridable Property FirstName As String
Here there is a new tag, value
. The summary
tag describes a property, and value
describes the property’s value. Do the same thing on the LastName
property, specifying the appropriate description, similarly to FirstName
. Other tags can be added in a straightforward way, thanks to the always present IntelliSense. Figure 49.6 shows how IntelliSense provides available XML tags, according to the particular context where they have to be added.
XML comments enable references to other code elements with specific tags. The first one is c
that identifies the element within angle bracket as code. To show an example, rewrite XML comments for the GetFullName
method as follows:
''' <summary>
''' Gets the complete person's name
''' </summary>
''' <returns>String</returns>
''' <remarks>This method concatenates <c>LastName</c> and
''' <c>FirstName</c> properties</remarks>
Public Overridable Function GetFullName() As String
Dim fn As New Text.StringBuilder
fn.Append(Me.FirstName)
fn.Append(" ")
fn.Append(Me.LastName)
Return fn.ToString
End Function
Notice how the c
tag embraces both the LastName
and FirstName
properties, communicating to the compiler that both tags represent a code element. It is enclosed and nested within a remarks tag (IntelliSense can be helpful in choosing the allowed tags). This is not the only way of referring to code; you can provide an entire code example that will be included in your documentation. To accomplish this, you first declare a sample tag, which contains the sample description and then a code tag that contains a code snippet demonstrating the member purpose. Edit the preceding XML comment as follows:
''' <summary>
''' Gets the complete person's name
''' </summary>
''' <returns>String</returns>
''' <remarks>This method concatenates <c>LastName</c> and
''' <c>FirstName</c> properties
''' <example>This example shows how you can invoke
''' the <c>GetFullName</c> method
''' <code>
''' Dim result As String = Person1.GetFullName()
''' </code>
''' </example>
''' </remarks>
Public Overridable Function GetFullName() As String
This is useful because your documentation also shows examples of your libraries.
Why Don’t I See Them?
Code
, c
, and example
tags provide documentation that is not available within IntelliSense. It is, however, available within the generated XML file; thus you can appreciate them when building an HTML-based or compiled documentation or within the Object Browser.
XML comments enable you to easily refer to and document members’ arguments. For a better understanding, write the following overload of the GetFullName
method that accepts a Title
argument:
Public Overridable Function GetFullName(ByVal Title As String) As String
If String.IsNullOrEmpty(Title) = True Then Throw New _
ArgumentNullException
Dim fn As New Text.StringBuilder
fn.Append(Title)
fn.Append(" ")
fn.Append(Me.FirstName)
fn.Append(" ")
fn.Append(Me.LastName)
Return fn.ToString
End Function
Now add an XML comment. It looks likes this:
''' <summary>
''' Gets the complete person's name
''' </summary>
''' <param name="Title"></param>
''' <returns>String</returns>
''' <remarks></remarks>
Public Overridable Function GetFullName(ByVal Title As String) As String
The param
tag enables you to referr to a member’s argument, specified by the name attribute. If you try to type the name on your own, IntelliSense helps you choose the argument. XML comments also enable you to specify an exception that your member could encounter, according to the actions it takes. For example, the GetFullName
method could throw a NullReferenceException
if the Title
argument is an empty or null string. For this, you use an exception
tag to specify the exception. The tag is used with cref
. This one is straightforward in that it enables you to point a reference to a .NET object using IntelliSense. The following tag (which must be added before the method definition) specifies which exception can be thrown:
''' <exception cref="ArgumentNullException">
''' The exception that is thrown when <paramref name="Title"/> is Nothing
''' </exception>
''' <returns>String</returns>
''' <remarks></remarks>
Public Overridable Function GetFullName(ByVal Title As String) As String
When typing cref
, the IntelliSense window shows all the available objects. You pick the exception you are interested in. This speeds up the way you write your comment, also ensuring that you type a valid object name. You can also specify the description for the exception. The good news about cref
is that it creates a cross-reference to the documentation related to the pointed object. For instance, when you create a compiled documentation file based on the XML comments, cref
enables you to redirect to another page showing information on the pointed object. You can also refer to the argument by specifying the paramref
tag within a descriptive text, which requires a name attribute pointing to the argument. paramref
also takes advantages of IntelliSense.
The Visual Basic compiler can link documentation to your code from an external XML document. To do this, you use the include
tag. The tag requires a file attribute that points to the external document and a path attribute that points to the position in the document providing documentation for the given member. The following code sets external documentation for the Age
property:
''' <include file="ExternalDoc.xml" path="Help/Property[@name='Age']"/>
Public Overridable Property Age As Integer
To understand how the path tag works, here is the XML representation of the external document:
<?xml version="1.0" encoding="utf-8" ?>
<Help>
<Property name="Age">
<summary>Returns how old a person is</summary>
<returns>Integer</returns>
</Property>
<!–– Other properties...––>
<Property>
</Property>
</Help>
Documentation often requires bulleted and numbered lists or tables, as in any other kind of document. Luckily, XML comments enable you to easily build lists. You do this with the list
tag that requires a type
attribute specifying whether the list is a bulleted or numbered list or a two-column table. The following example shows how to build a numbered list on the Person
class documentation:
''' <summary>
''' Represents a human being
''' </summary>
''' <remarks>
''' <list type="number">
''' <item><description>Instantiate the class</description></item>
''' <item><description>Populate its properties</description></item>
''' <item><description>Eventually retrieve the full
''' name</description></item>
''' </list>
''' </remarks>
Public Class Person
....
End Class
The type attribute can have one of the following values: bullet
(bulleted list), number
(numbered list), or table
(two-column table). Notice how each item in the list is represented by an item tag that requires a nested description tag providing the actual description. If you want to provide a table, each item must contain a term tag and a description tag as in the following example:
''' <item><term>Action one</term></item>
''' <item><description>Instantiate the class</description></item>
The item’s content will be also shown in IntelliSense and the Object Browser, but it will be formatted as a list only in the compiled documentation.
Sometimes your objects expose members that require special permissions to access system resources. You can provide documentation about required permissions by adding a permission tag with cref
, pointing to the desired .NET permission. The following example shows how to comment the GetFullName
method with the UIPermission
requirement:
''' <permission cref="System.Security.Permissions.UIPermission"/>
Public Overridable Function GetFullName() As String
Of course, you can specify multiple permissions by adding multiple permission tags.
When documenting the code, it is not unusual to provide links to other members. XML comments enable you to do this by specifying see
and seealso
tags. The see
tag enables you to specify a link to another member’s documentation from within the description text. The seealso
tag does the same, but it differs in that the link to the other member appears in the See Also section of the compiled page. The following example demonstrates this on the FirstName
property providing a link to LastName
:
''' <remarks>Use the <see cref="LastName"/>
''' property for the person's last name</remarks>
Public Overridable Property FirstName As String
If you want the link to be shown in the See Also section, replace see
with seealso
.
When you define your custom generics, you can use XML comments to describe the type parameter. This is accomplished via the typeparam
tag, as shown in the following code snippet:
''' <summary>
''' A test class
''' </summary>
''' <typeparam name="T">
''' A type parameter that must implement IEnumerable
''' </typeparam>
''' <remarks></remarks>
Public Class TestGenerics(Of T As IEnumerable)
End Class
The Visual Basic compiler automatically recognizes the generic implementation and thus adds for you the typeparam
tag when adding the XML comment.
When you document your source code with XML comments, you might want to generate compiled help files that you can distribute together with your libraries. Compiled help files are .chm files that can be easily opened with the Windows integrated Help Viewer. The .chm file format is the most appropriate in such situations because it is a standalone and does not require additional applications. Several tools can generate .chm files starting from XML comments. A very popular one is SandCastle, an open source tool from Microsoft that is also used to build documentation. At the moment in which this chapter is being written, SandCastle supports Visual Studio 2010 so our suggestion is to check out the SandCastle website (http://www.codeplex.com/sandcastle) periodically to see if an update is available. Also, a number of third party (paid) tools exist on the market. Popular tools are the following:
• Help + Manual from EC Software (http://www.ec-software.com)
• HelpNDoc (http://www.helpndoc.com)
These tools are very good in that they enable you to generate multiple output formats, not only .chm files.
This chapter covered how to use XML comments instead of classic comments. With XML comments, you specify tags that identify an element in the code as a special formatted element in the generated documentation file. Such a file is an XML document that enables IntelliSense documentation for your own code and constitutes the source for automating building compiled help files that accompany your libraries as the documentation. To automate this process, you were informed about the existence of Microsoft SandCastle, a free tool from Microsoft that is available on CodePlex as an open-source application, and of tools produced by other vendors.