五、生成源代码
生成具体语言的源代码需要一个从CodeDomProvider继承的类。对于C#而言是CSharpCodeProvider类。实现代码如下:
using Microsoft.CSharp;public
void SaveCSharp(String filename){IndentedTextWriter tw =
new IndentedTextWriter(new StreamWriter(filename, false), "
");CodeDomProvider provide =
new CSharpCodeProvider();provide.GenerateCodeFromCompileUnit(m_CodeCompileUnit, tw, new CodeGeneratorOptions());tw.Close();}
在使用CSharpCodeProvider类时需要用到m_CodeCompileUnit这个全局变量。这样可产生一个*.cs文件。以上代码中的 IndentedTextWriter类是建立一个文件的Writer,用于向这个文件中输出源代码。但和其它的Writer不同的是它的输出是缩进的 (以四个空格进行缩进)。如是想生成VB.net的代码,只需将CSharpCodeProvider改为VBCodeProvider即可。
编译源代码
到现在为止,这个数据表类的源代码已经全部生 成了。你可以将这个源文件直接加入到自己的工程中。或者直接将其编译成*.dll文件,然后在程序中调用。如果想编译,可以直接调用指定语言的编译器(如 C#中的csc.exe)。但这样不是太方便。在CodeDOM中提供了一种机制,可以在程序中通过CodeDomProvider直接调用指定语言的编 译器。下面是编译C#源程序的一个例子。
public
void CompileCSharp(String sourcefile, String targetFile){CompilerParameters cp =
new CompilerParameters(new String[] { "System.Xml.dll" }, targetFile, false);CodeDomProvider provider =
new CSharpCodeProvider();cp.GenerateExecutable =
false;// 调用编译器
CompilerResults cr = provider.CompileAssemblyFromFile(cp, sourcefile);if (cr.Errors.Count >
0){// 显示编译错误
foreach (CompilerError ce in cr.Errors)System.Windows.Forms.MessageBox.Show(ce.ToString());}}
对于以上代码有两点说明:
- 使用CodeDomProvider调用编译器时也需要传递相应的参数,如在本例中将System.Xml.dll
作为一个参数,表示目标文件需要调用这个dll中的资源。
- 在调用编译器后,如果出现错误,可使用cr.Errors获得错误信息。
结束语
我花了一个晚上的时间实现了这个简单的例子,并用C#2.0调试通过,只是为了抛砖引玉。自动生成源代码有很多的方法,但使用CodeDom生成源代码会有更大的灵活性,主要表现在以下三个方面:
1.
语言无关。即只要是.net framework所支持的语言,并且这种语言提供了CodeDomProvider。
就可以生成这种语言的源代码。
2.
如果所生成的语言是测试版或要将这种语言升级到下一个版本,也可以考虑使用CodeDOM。
因为当这种语言的语法有所变化时,CodeDomProvider也会随之升级。因此,使用CodeDOM的Code Wizards也会随着CodeDOM而升级,这样就不必修改Code Wizards的源代码了。
3.
如果所生成的一种语言是你所不熟悉的,如果不使用CodeDOM,必须要熟悉这种语言的语
法,才能生成它的源代码。而使用CodeDOM却可以避免这一点。因为CodeDOM是使用抽象的object graph来描述语言的。而语言的具体语法是由CodeDomProvider所决定的。
其实CodeDOM不仅可以用在Code Wizards上,也可以用在许多其它地方,如可以生成Web
Services的客户端代理(Client Proxies),或根据UML图生成类的构架代码。总之,使用CodeDom可以大大降低和语言的偶合度,并且很容易维护和升级系统