题外话,我最近怎么总是在周二写Blog啊?看看Blog上的日历,全都是周二写的!^_^
言规正传,最近为了一个项目需要动态生成代码特地写了另一个小“项目”,动态代码生成器。其实就是动态的模板,一个有差不多ASP.NET语法的模板,应该说与CodeSmith的功能是一样的,只不过现在还没有编辑器。目前提供了一个DLL,可以提供所有需要构建一个模板编辑器所需要的信息,包括动态模板的编译时错误以及运行时错误等。
我在这个小项目中运用了很多学到的新知识,自我感觉在这个小项目中运用的设计是目前为止运用的最好的一次。^_^
下面描述一下模板的语法与使用方法:
@ Template Language="C#" Name="" Version=""
1
2 * ```
3@ Parameter Name="ParamName" DataType="System.String" AssemblyName=""
4```:模板参数,其中的所有属性都是必须的,当参数类型的的所在程序集为mscorlib.dll时需要将AssemblyName属性设为空。一个模板可以有多个参数。
5
6 * ```
7 code
8```:模板中的动态代码,在其中可以用模板Language属性所指定的语言写入动态代码。
9
10 * ```
11= variable
12```:模板中的动态代码,会将动态代码的结果返回,注意如果动态代码不返回任何结果的话,那么就会产生编译错误。
13
14 * ```
15# void Method()
16```:动态方法,在模板中可以简单的定义动态方法,这样就可以直接在其他动态代码部分调用这个动态方法。
17
18 * ```
19-- comment --
20```:动态模板中的注释。
21
22
23
24
25模板本身不是Case Sensitive,不过每个Tag属性中的值就要根据模板运用的语言来定是否是Case Sensitive了。比如如果是C#,那么就是Case Sensitive,如果是VB.NET那就不是了。
26
27下面是C#的示例:
28
29模板为:
@ Template Name="Sample1" Version="1.0" language="C#"
@ Parameter Name="Entity" DataType="Kefroth.Entity" AssemblyName="DCGTest.exe"
1
2using System;
3
4// 这是一段中文注释。
-- 模板注释 --
1namespace ```
2= Entity.Namespace
3``` {
4public sealed class ```
5=Entity.Name
6``` {
7public static void CallMe() {
8ArrayList list = new ArrayList();
for (int i = 1; i <= 10; i++) {
1list.Add("```
2= GetEntityName() + i
3```");
}
1}
2}
3}
string GetEntityName() {
return Entity.GetFullName();
}
1
2调用模板的代码为:
3
4string fileContent = this.ReadFile(Application.StartupPath + "\\\" + "Sample Template.dt");
5
6Entity ent = new Entity();
7ent.Namespace = "SampleNamespace";
8ent.Name = "SampleEntity";
9ITemplateManager templateManager = new TemplateManager();
10try {
11ITemplate template = templateManager.NewTemplate(fileContent);
12this.textBox1.SelectedText += "This template's name is: " + template.Name + Environment.NewLine;
13this.textBox1.SelectedText += "This template's language is: " + template.Language + Environment.NewLine + Environment.NewLine;
14this.textBox1.SelectedText += template.GenerateCode(new object[] {ent});
15} catch (CompileTimeException ex) {
16this.textBox1.Clear();
17foreach (CompilerError error in ex.CompilerResults.Errors) {
18this.textBox1.SelectedText += error.ErrorText + Environment.NewLine;
19}
20return;
21} catch (RunTimeException ex) {
22this.textBox1.Clear();
23this.textBox1.SelectedText += ex.InnerException.InnerException.ToString() + Environment.NewLine;
24return;
25} catch (TemplateException ex) {
26this.textBox1.Clear();
27this.textBox1.SelectedText += ex.ToString() + Environment.NewLine;
28return;
29}
30
31结果为:
32
33This template's name is: Sample1
34This template's language is: C#
35
36using System;
37
38// 这是一段中文。
39namespace SampleNamespace {
40public sealed class SampleEntity {
41public static void CallMe() {
42ArrayList list = new ArrayList();
43list.Add("SampleNamespace.SampleEntity1");
44list.Add("SampleNamespace.SampleEntity2");
45list.Add("SampleNamespace.SampleEntity3");
46list.Add("SampleNamespace.SampleEntity4");
47list.Add("SampleNamespace.SampleEntity5");
48list.Add("SampleNamespace.SampleEntity6");
49list.Add("SampleNamespace.SampleEntity7");
50list.Add("SampleNamespace.SampleEntity8");
51list.Add("SampleNamespace.SampleEntity9");
52list.Add("SampleNamespace.SampleEntity10");
53}
54}
55}
56
57从代码中可以看出调用是非常简单的,而且可以非常轻松的集成在任何项目中,这就达到了我的初始目的。CodeSmith可以做到这一切,当却不能轻松的集成到其他项目中去。
58
59这样一个动态代码生成器的用途无异是非常广的,不过我希望看到这篇文章的读者能够给我提出更好的意见,或是讨论,来使DCG更加完美!^_^