这是C#代码(和我们开始提到过的完全一致):
This code was generated by a tool.
Runtime Version:4.0.30319.1
Changes to this file may cause incorrect behavior and will be lost if
the code is regenerated.
</auto-generated>
namespace Artech.CodeDomGenerator {
public class Messages {
public class Validation {
public static Artech.CodeDomGenerator.MessageEntry MandatoryField = new Artech.CodeDomGenerator.MessageEntry("MandatoryField", "The {0} is mandatory.", "Validation");
public static Artech.CodeDomGenerator.MessageEntry GreaterThan = new Artech.CodeDomGenerator.MessageEntry("GreaterThan", "The {0} must be greater than {1}.", "Validation");
}
public class Confirmation {
public static Artech.CodeDomGenerator.MessageEntry ReallyDelete = new Artech.CodeDomGenerator.MessageEntry("ReallyDelete", "Do you really want to delete the {0}.", "Confirmation");
}
}
}
下面是VB.NET代码:
This code was generated by a tool.
Runtime Version:4.0.30319.1
Changes to this file may cause incorrect behavior and will be lost if
the code is regenerated.
</auto-generated>
Option Strict Off
Option Explicit On
Namespace Artech.CodeDomGenerator
Public Class Messages
Public Class Validation
Public Shared MandatoryField As Artech.CodeDomGenerator.MessageEntry = New Artech.CodeDomGenerator.MessageEntry("MandatoryField", "The {0} is mandatory.", "Validation")
Public Shared GreaterThan As Artech.CodeDomGenerator.MessageEntry = New Artech.CodeDomGenerator.MessageEntry("GreaterThan", "The {0} must be greater than {1}.", "Validation")
End Class
Public Class Confirmation
Public Shared ReallyDelete As Artech.CodeDomGenerator.MessageEntry = New Artech.CodeDomGenerator.MessageEntry("ReallyDelete", "Do you really want to delete the {0}.", "Confirmation")
End Class
End Class
End Namespace
在前面,我们实现了将保存有消息条目的XML向CodeDOM的转换,即是将XML文件生成一个CodeCompileUnit对象,而该CodeCompileUnit对象反映出来的DOM层次和我们将会生成的代码文件向匹配。在下篇中,我们将实现整个代码生成系统的第二个步骤——通过VS的Custom Tool实现数据(保存消息条目的XML)向代码文件的自动转换。
一、让MessageCodeGenerator继承BaseCodeGeneratorWithSite
在前面我们创建了MessageCodeGenerator类,定义了如下一个BuildCodeObject方法实现将一个XmlDocument转换成一个CodeCompileUnit对象。
{
public class MessageCodeGenerator
{
// Others...
public CodeCompileUnit BuildCodeObject(XmlDocument messages);
}
}
现在我们需要做的是让这个MessageCodeGenerator继承一个特殊的类:BaseCodeGeneratorWithSite。BaseCodeGeneratorWithSite所在的程序集名称为Microsoft.VisualStudio.TextTemplating.VSHost.10.0.dll,这是一个Visual Studio SDK的程序集。我们例子采用的是Visual Studio 2010,你可以在如下的目录中找到该程序集:%ProgramFiles%Microsoft Visual Studio 2010 SDK\VisualStudioIntegration\Common\Assemblies\v4.0。如果你没有安装VS 2010 SDK,你可以从这里下载。
除了添加对Microsoft.VisualStudio.TextTemplating.VSHost.10.0.dll程序集的引用外,你还需要添加两个额外的程序集引用:Microsoft.VisualStudio.OLE.Interop.dll和Microsoft.VisualStudio.Shell.Interop.dll,它们所在的目录分别是%ProgramFiles%Microsoft Visual Studio 2010 SDK\VisualStudioIntegration\Common\Assemblies\v4.0和%ProgramFiles%Microsoft Visual Studio 2010 SDK\VisualStudioIntegration\Common\Assemblies\v2.0。
添加了相应的程序集引用,并将BaseCodeGeneratorWithSite这个抽象类作为MessageCodeGenerator的基类后,需要实现如下两个抽象方法:GenerateCode和GetDefaultExtension。
{
public class MessageCodeGenerator : BaseCodeGeneratorWithSite
{
public CodeCompileUnit BuildCodeObject(XmlDocument messages)
{
//......
}
protected override byte[] GenerateCode(string inputFileName, string inputFileContent)
{
var messageDoc = new XmlDocument();
messageDoc.LoadXml(inputFileContent);
var codeObject = BuildCodeObject(messageDoc);
CodeDomProvider provider = CodeDomProvider.CreateProvider("CSharp");
CodeGeneratorOptions options = new CodeGeneratorOptions();
options.BracingStyle = "C";
using (StringWriter writer = new StringWriter())
{
provider.GenerateCodeFromCompileUnit(codeObject, writer, options);
string code = writer.ToString();
byte[] preambleBytes = Encoding.Unicode.GetPreamble();
byte[] codeBytes = Encoding.Unicode.GetBytes(code);
byte[] result = new byte[preambleBytes.Length + codeBytes.Length];
Buffer.BlockCopy(preambleBytes, 0, result, 0, preambleBytes.Length);
Buffer.BlockCopy(codeBytes, 0, result, preambleBytes.Length, codeBytes.Length);
return result;
}
}
public override string GetDefaultExtension()
{
return ".cs";
}
}
}
GenerateCode返回的字节数组表示最终生成的的代码的内容,在这里的逻辑很简单,就是通过CodeDomProvider将CodeCompileUnit转化成基于具体编程语言(在这里我们只考虑C#)的代码。而GetDefaultExtension返回生成的代码文件的扩展名,在这里自然是“.cs”。