O'Reilly logo

C# in a Nutshell by Peter Drayton, Ted Neward, Ben Albahari

Stay ahead with the world's most comprehensive technology and business learning platform.

With Safari, you learn the way you learn best. Get unlimited access to videos, live online training, learning paths, books, tutorials, and more.

Start Free Trial

No credit card required

XML Documentation

C# offers three different styles of source-code documentation: single-line comments, multiline comments, and documentation comments.

C/C++-Style Comments

Single- and multiline comments use the C++ syntax: // and /*...*/:

int x = 3; // this is a comment
MyMethod(); /* this is a
comment that spans two lines */

The disadvantage of this style of commenting is that there is no predetermined standard for documenting types. Consequently, it cannot be easily parsed to automate the production of documentation. C# improves on this by allowing you to embed documentation comments in the source, and by providing an automated mechanism for extracting and validating documentation at compile time.

Documentation Comments

Documentation comments are similar to C# single-line comments, but start with /// (that’s three slashes), and can be applied to any user-defined type or member. As well as containing descriptive text, these comments can also include embedded XML tags. These tags allow one to mark up the descriptive text to better define the semantics of the type or member, and also to incorporate cross-references.

These comments can then be extracted at compile time into a separate output file containing the documentation. The compiler validates the comments for internal consistency, expands cross-references into fully qualified type IDs, and outputs a well-formed XML file. Further processing is left up to you, although a common next step is to run the XML through XSLT, generating HTML documentation.

Here is an example of documentation comments for a very simple type:

// Filename: DocTest.cs
using System;
class MyClass {
  /// <summary>
  /// The Foo method is called from
  ///   <see cref="Main">Main</see> 
  /// </summary>
  /// <mytag>Secret stuff</mytag>
  /// <param name="s">Description for s</param>
  static void Foo(string s) { Console.WriteLine(s); }
  static void Main() { Foo("42"); }
}

XML Documentation Files

When run through the compiler using the /doc:< filename> command-line option, the following XML file is generated:

<?xml version="1.0"?>
<doc>
  <assembly>
    <name>DocTest</name>
  </assembly>
  <members>
    <member name="M:MyClass.Foo(System.String)">
      <summary>
      The Foo method is called from
        <see cref="M:MyClass.Main">Main</see> 
      </summary>
      <mytag>Secret stuff</mytag>
      <param name="s">Description for s</param>
     </member>
  </members>
</doc>

The <?xml...>, <doc>, and <members> tags are generated automatically and form the skeleton for the XML file. The <assembly> and <name> tags indicate the assembly this type lives in. Every member that was preceded by a documentation comment is included in the XML file via a <member> tag with a name attribute that identifies the member. Note that the cref attribute in the <see> tag has also been expanded to refer to a fully qualified type and member. The predefined XML documentation tags that were embedded in the documentation comments are also included in the XML file, and have been validated to ensure that all parameters are documented, that the names are accurate, and that any cross-references to other types or members can be resolved. Finally, any additional user-defined tags are transferred verbatim.

Predefined XML Tags

The predefined set of XML tags that can be used to mark up the descriptive text are listed here:

<summary>

<summary>description</summary>

This tag describes a type or member. Typically, <summary> contains the description of a member at a fairly high level.

<remarks>

<remarks>description</remarks>

This tag provides additional information regarding a particular member. Information about side effects within the method, or particular behavior that may not otherwise be intuitive (such as the idea that this method may throw an ArrayOutOfBoundsException if a parameter is greater than 5) is listed here.

<param>

<param name="name">description</param>

This tag describes a parameter on a method. The name attribute is mandatory, and must refer to a parameter on the method. If this tag is applied to any parameter on a method, all of the parameters on that method must be documented. Enclose name in double quotation marks ("").

<returns>

<returns>description</returns>

This tag describes the return values for a method.

<exception>

<exception [cref="type"]>description</exception>

This tag documents the exceptions a method may throw. If present, the optional cref attribute should refer to the type of the exception. The type name must be enclosed in double quotation marks ("").

<permission>

<permission [cref="type"]>description</permission>

This tag documents the permissions requirement for a type or member. If present, the optional cref attribute should refer to the type that represents the permission set required by the member, although the compiler does not validate this. The type name must be enclosed in double quotation marks ("").

<example>

<example>description</example>

This tag provides a description and sample source code explaining the use of a type or member. Typically, the <example> tag provides the description and contains the <c> and <code> tags, although they can also be used independently.

<c>

<c>code</c>

This tag indicates an inline code snippet. Typically, this tag is used inside an <example> block (described previously).

<code>

<code>code</code>

This tag is used to indicate multiline code snippets. Again, this is typically used inside of an <example> block (described previously).

<see>

<see cref="member">text</see>

This tag identifies cross-references in the documentation to other types or members. Typically, the <see> tag is used inline within a description, (as opposed to the <seealso> tag, which is broken out into a separate “See Also” section). This tag is useful because it allows tools to generate cross-references, indexes, and hyperlinked views of the documentation. Member names must be enclosed by double quotation marks ("").

<seealso>

<seealso cref="member">text</seealso>

This tag identifies cross-references in the documentation to other types or members. Typically, <seealso> tags are broken out into a separate “See Also” section. This tag is useful because it allows tools to generate cross-references, indexes, and hyperlinked views of the documentation. Member names must be enclosed by double quotation marks ("").

<value>

<value>description</value>

This tag describes a property on a class.

<paramref>

<paramref name="name"/>

This tag identifies the use of a parameter name within descriptive text, such as <remarks>. The name must be enclosed by double quotation marks ("").

<list>
<list type=[ bullet | number | table ]>
  <listheader>
    <term>name</term>
    <description>description</description>
  </listheader>
  <item>
    <term>name</term>
    <description>description</description>
  </item>
</list>

This tag provides hints to documentation generators about how to format the documentation — in this case, as a list of items.

<para>

<para>text</para>

This tag sets off the text as a paragraph to documentation generators.

<include>

<include file='filename' path='path-to-element'>

This tag specifies an external file that contains documentation and an XPath path to a specific element in that file. For example, a path of docs[@id="001 " ]/* retrieves whatever is inside of <docs id="001"/>. The filename and path must be enclosed by single quotation marks (''), but you must use double quotation marks ("") for the id attribute within the path-to-element expression.

User-Defined Tags

There is little that is special about the predefined XML tags recognized by the C# compiler, and you are free to define your own. The only special processing done by the compiler is on the <param> tag (in which it verifies the parameter name and that all the parameters on the method are documented) and the cref attribute (in which it verifies that the attribute refers to a real type or member, and expands it to a fully qualified type or member ID). The cref attribute can also be used in your own tags, and is verified and expanded just as it is in the predefined <exception>, <permission>, <see>, and <seealso> tags.

Generated Documentation

Once an XML file is generated from documentation comments, it typically requires another step before becoming generally useful to programmers, since most of us aren’t quite able to parse and use an XML file “in the raw.”

The most common approach is to run the XML output through an XSLT stylesheet to generate some more human-friendly format, such as HTML. (Variations on this idea include generating PDF, RTF, or even Microsoft Word documents.) While Microsoft may publish a standardized XSLT file for this, companies may want to create their own to establish their own “look” for documentation of components they sell. Alternatively, several open source projects have already begun to explore this area, and produce neatly formatted documentation files; one example is http://ndoc.sourceforge.net.

The ability to put user-defined tags into the XML documentation sections represents a powerful extensibility point — for example, a company may put implementation details about the method or class inside of <implementation> tags and define two XSLT files: one excluding the implementation tags, and the other including it. The non-<implementation>-aware files can be distributed publicly, while the <implementation>-aware files are used internally by developers. An automated test tool might run tests against those methods or classes described by a <test name=test-to-run> tag. Types meant to be stored in the database might use XML documentation tags to indicate the SQL required to create the tables, and a custom tool could be written to extract the necessary SQL from the XML documentation files in order to run it. Non-public information about the code can be embedded within the code itself or in the documentation comments and processed by an external tool via this mechanism, which makes it quite powerful.

Type or Member Cross-References

Type names and type or member cross-references are translated into IDs that uniquely define the type or member. These names are composed of a prefix that defines what the ID represents and a signature of the type or member.

Table 4-4 lists the set of type or member prefixes.

Table 4-4. XML type ID prefixes

XML type prefix

ID prefixes applied to

N

Namespace

T

Type (class, struct, enum, interface, delegate)

F

Field

P

Property (includes indexers)

M

Method (includes special methods)

E

Event

!

Error

The rules describing how the signatures are generated are well documented, although fairly complex.

Here is an example of a type and the IDs that are generated:

// Namespaces do not have independent signatures
namespace NS {
  /// T:NS.MyClass
  class MyClass {
    /// F:NS.MyClass.aField
    string aField;
    /// P:NS.MyClass.aProperty
    short aProperty {get {...} set {...}}
    /// T:NS.MyClass.NestedType
    class NestedType {...};
    /// M:NS.MyClass.X()
    void X() {...}
    /// M:NS.MyClass.Y(System.Int32,System.Double@,System.Decimal@)
    void Y(int p1, ref double p2, out decimal p3) {...}
    /// M:NS.MyClass.Z(System.Char[],System.Single[0:,0:])
    void Z(char[] p1, float[,] p2) {...}
    /// M:NS.MyClass.op_Addition(NS.MyClass,NS.MyClass)
    public static MyClass operator+(MyClass c1, MyClass c2) {...}
    /// M:NS.MyClass.op_Implicit(NS.MyClass)~System.Int32
    public static implicit operator int(MyClass c) {...}
    /// M:NS.MyClass.#ctor
    MyClass() {...}
    /// M:NS.MyClass.Finalize
    ~MyClass() {...}
    /// M:NS.MyClass.#cctor
    static MyClass() {...}
  }
}

With Safari, you learn the way you learn best. Get unlimited access to videos, live online training, learning paths, books, interactive tutorials, and more.

Start Free Trial

No credit card required