把 Visual Studio .NET 源代码文件中C# XML注释提取成工程文档
作者: J. Andrew Schafer
这篇文章假设你对 XML, XSLT, 和 C# 熟悉
下载这篇文章的源代码: XMLC.exe (76KB)
译者说明:这篇文章是很早以前就发表了,它提供的源代码是基于 VS.net 测试版(RTM 和 Beta 2)的。
摘要
C# 允许开发人员在源代码中插入XML注释,这在多人协作开发的时候显得特别有用。 C#解析器可以把代码文件中的这些XML标记提取出来,并作进一步的处理为外部文档。 这篇文章将展示如何使用这些XML注释。作者演示了如何生成工程,如何把XML注释输出为有用文档,如何把这些注释转变为帮助文件。 在项目开发中,很多人并不乐意写繁杂的文档。但是,开发组长希望代码注释尽可能详细;项目规划人员希望代码设计文档尽可能详尽;测试、检查人员希望功能说明书尽可能详细等等。 如果这些文档都被要求写的话,保持它们同步比进行一个战役还痛苦。
为何不把这些信息保存在一个地方呢??最明显想到的地方就是代码的注释中;但是你很难通览程序,并且有些需要这些文档的人并不懂编码。
这篇文章将展示如何通过使用XML注释来解决这些问题。代码注释、用户手册、开发人员手册、测试计划等很多文档可以很方便的从XML注释中获得。我将先演示如何插入XML注释、如何把这些XML注释导出为另一个文档。然后再讨论每个XML标记的意思,以及使用XML和XSL生成帮助文件。
所有的XML注释都在三个向前的斜线之后(///)。两条斜线表示是一个注释,编译器将忽略后面的内容。三条斜线告诉编译器,后面是XML注释,需要适当地处理。
当开发人员输入三个向前的斜线后,Microsoft Visual Studio .NET IDE 自动检查它是否在类或者类成员的定义的前面。如果是的话,Visual Studio .NET IDE 将自动插入注释标记,开发人员只需要增加些额外的标记和值。下面就是在成员函数前增加三个斜线,自动增加的注释:
/// <summary> /// /// </summary> /// <param name="strFilePath"></param> public void LoadXMLFromFile(string strFilePath)这里嵌入的标记仅仅是Visual Studio .NET IDE 的一部分标记,然而在IntelliSense for xml中,并没有把c#规范中所有的标记列出来,遗失的部分只能用手工插入。
这些手工标记是非常有用的,如果恰当地设置他们,对导出成外部说明文件将非常有帮助。
如果碰到是预先定义的xml标记,编译器可以把这些注释以文本输出;如果是编译器不认识的xml标记,编译器会逐字的把所有内容都输出,这意味着你可以使用自己定义的标记。
适当的设置,C#编译器并不格式化xml注释,而是以xml文件输出。下面的步骤将演示如何让C#编译器把xml注释输出为xml文件
- 右键点击解决方案资源管理器中的工程项,打开工程的属性页,点击属性。
- 对话框出现后,点击配置属性目录。
- 点击生成节点。
- 在右边的框中有 输出--xml文档文件,这里就是设置丛xml注释生成xml文件的文件名。(注:这里设置的是相对路径,不是绝对路径)
图一 配置xml注释输出
公认的标记
我把xml注释标记分类两大类:第一类是设置标记,我叫他们主标记。他们在一组标记的开始,而且不会在标记内部出现。 第二类是设置标记包含的标记,我叫他们支持标记。支持标记和html标记的区别在于:支持标记采用的是小写,html标记采用的是大写。 图2显示了我将要讨论的支持标记和主标记。
图2 GiveHelpTransforms.cs 部分代码
namespace GiveHelp { /// <remarks> /// Class that contains functions to do transformations to help files. /// The source XML is loaded into the <see cref="SourceXML"/> property /// (e.g. <c><I>obj</I>.SourceXML = "<I>XML goes here</I>"</c>). One of /// the associated member functions (<see cref="GiveTypeListHTMLHelp"/ /// >, <see cref="GiveMemberListHTMLHelp"/>, <see /// cref="GiveMemberHTMLHelp"/>) /// is called to initiate and then return the transformation. /// <para> /// <list type="table"> /// <listheader> /// <term>Help Page</term> /// <description>Function to call</description> /// </listheader> /// <item><term>List of Types</term> /// <description>GiveTypeListHTMLHelp</description></item> /// <item><term>List of members</term> /// <description>GiveMemberListHTMLHelp</description></item> /// <item><term>Help for a single member</term> /// <description>GiveMemberHTMLHelp</description></item> /// </list> /// </para> /// </remarks> /// <permission cref="">public</permission> /// <example><code> /// // create the class that does translations /// GiveHelpTransforms ght = new GiveHelpTransforms(); /// // have it load our XML into the SourceXML property /// ght.LoadXMLFromFile("E://Inetpub//www- /// root//GiveHelp//GiveHelpDoc.xml"); /// /// // do the translation and then write out the string /// Response.Write( ght. /// GiveMemberHTMLHelp(Request.QueryString.Get("Type"), /// Request.QueryString.Get("Member")) ); /// </code></example> public class GiveHelpTransforms { ??? /// <summary> /// Calling this function will take the XML in <see /// cref="SourceXML"/> /// and translate it to a list of Members in the specified type. /// </summary> /// <param name="strType">The fully qualified name of the type that /// the member is in.</param> /// <returns>The HTML that lists the types that are in the XML /// documentation.</returns> /// <seealso cref="GiveTypeListHTMLHelp"/> /// <seealso cref="GiveMemberHTMLHelp"/> /// <example><code> /// // create the class that does translations /// GiveHelpTransforms ght = new GiveHelpTransforms(); /// // have it load our XML into the SourceXML property /// ght.LoadXMLFromFile( /// "E://Inetpub//wwwroot//GiveHelp//GiveHelpDoc.xml"); /// /// // do the translation and then write out the string /// Response.Write( /// ght.GiveMemberListHTMLHelp(Request. /// QueryString.Get("Type"))); /// </code></example> /// <permission cref="">public</permission> public string GiveMemberListHTMLHelp(string strType) { // Load the corresponding XSLT XslTransform xslTransformFile = new XslTransform(); xslTransformFile.Load( "E://Inetpub//wwwroot//GiveHelp//GiveTypeMemberListHelp.xsl"); // create the output repository for the transform System.Text.StringBuilder sbTransformed = new System.Text.StringBuilder(); System.IO.TextWriter tw = (System.IO.TextWriter)new System.IO.StringWriter(sbTransformed); // the strType parameter is passed into the stylesheet XsltArgumentList arglist = new XsltArgumentList(); arglist.AddParam("WhichType","",strType); xslTransformFile.Transform(m_xdSourceXML,arglist,tw); return tw.ToString(); } }这里有九个主标记: <remarks>, <summary>, <example>, <exception>, <param>, <permission>, <returns>, <seealso>, 和<include>.
在上下文中,<remarks>描述了这个类的细节。
/// <remarks> /// Class that contains functions to do /// transformations to help files. /// </remarks>C#文档推荐使用<remarks>描述一个对象,<summary>描述一个对象成员。奇怪的是如果你用Visual Studio .NET IDE在一个类前输入///,他将自动增加<summary>,而不是<remarks> ,这时你需要手工输入<remarks>。
<summary>经常在C#文档中发现,这个标记用于描述类的成员,包括属性、方法、成员等。
/// <summary> /// This XmlDocument based attribute contains the /// XML documentation for the project. /// </summary><summary>也可以很好的描述对象,但是不推荐,xml注释文档推荐使用<remarks>描述对象。
<example>被用来演示如何使用,例子可以使任何正确的文本文件,但是更多是一小段代码:
/// <example> /// <code> /// // create the class that does translations /// GiveHelpTransforms ght = new GiveHelpTransforms(); /// // have it load our XML into the SourceXML property /// ght.LoadXMLFromFile( /// "E://Inetpub//wwwroot//GiveHelp//GiveHelpDoc.xml"); /// </code> /// </example>如果其中有代码,<code>经常被使用,<code>是将要被支持的一个标记。
<