一直想写一个Code生成系列,但写到CodeSimth,发觉在TerryLee 和努力学习的小熊 两位大牛的博客里讲很详尽,所以就像写些示例方面的,但是苦于没有想到写些什么。最近Artech写了两篇从数据到代码——通过代码生成机制实现强类型编程--上篇和下篇,大牛写得是CodeDom的,今天我就想借借大牛的示例写个CodeSimth版的,希望Artech不要怪我,呵呵。我的Code生成技术已经写了CodeDom的见CodeDom系列目录,欢迎各位园友指教。
好直接到主题。首先是数据实体MessageEntry(我到老A的基础上添加了description属性作为代码字段描述):
2 {
3 public class MessageEntry
4 {
5 public string Id { get; private set; }
6 public string Value { get; private set; }
7 public string Description { get; private set; }
8 public MessageEntry(string id, string value)
9 {
10 this.Id = id;
11 this.Value = value;
12 }
13
14 public MessageEntry(string id, string value, string description)
15 {
16 this.Id = id;
17 this.Value = value;
18 this.Description = description;
19 }
20
21 public string Format(params object[] args)
22 {
23 return string.Format(this.Value, args);
24 }
25 }
26 }
27
28
在我的机子上的COdeSimth是2..0版本的所以不能使用Linq命名空间,我又想利用这个空间,比较快捷,所以我就在先3.0转化为
Dictionary<string, List<MessageEntry>>实体再传入模板:
Code:
2 using System.Collections.Generic;
3 using System.Linq;
4 using System.Text;
5 using System.Xml;
6 using System.Xml.Linq;
7
8 namespace Wolf
9 {
10 public class MessageCodeGenerator
11 {
12 public Dictionary<string, List<MessageEntry>> GeneratorCode(string path)
13 {
14 return GeneratorCode(XElement.Load(path));
15 }
16 public Dictionary<string, List<MessageEntry>> GeneratorCode(XElement root)
17 {
18
19 var elemts = root.Elements("message").GroupBy(e => ((XAttribute)e.Attribute("category")).Value);
20 Dictionary<string, List<MessageEntry>> dict = new Dictionary<string, List<MessageEntry>>();
21 foreach (var item in elemts)
22 {
23 List<MessageEntry> list = new List<MessageEntry>();
24 foreach (var g in item)
25 {
26 if (g.Attribute("description") != null)
27 {
28 list.Add(new MessageEntry(((XAttribute)g.Attribute("id")).Value, ((XAttribute)g.Attribute("value")).Value, ((XAttribute)g.Attribute("description")).Value));
29 }
30 else
31 {
32 list.Add(new MessageEntry(((XAttribute)g.Attribute("id")).Value, ((XAttribute)g.Attribute("value")).Value));
33 }
34
35 }
36 dict.Add(item.Key.ToString(), list);
37 }
38 return dict;
39
40 }
41 }
42 }
43
44
这下几可开始写模板了,见下Code:
2
3 <%@ Import NameSpace="System" %>
4 <%@ Import NameSpace="System.Xml" %>
5 <%@ Import NameSpace="System.Text" %>
6 <%@ Import NameSpace="System.Collections.Generic" %>
7 <%@ Import NameSpace="Wolf" %>
8 <%@ Assembly Name="Wolf" %>
9
10 <script runat="template">
11
12 private Dictionary<string, List<MessageEntry>> dict;
13 public Dictionary<string, List<MessageEntry>> Generator
14 {
15 get
16 {
17 return dict;
18 }
19 set
20 {
21 dict=value;
22 }
23 }
24
25 public string GeneratorCode()
26 {
27 string str = "using Wolf;\r\nusing System;\r\nusing System.Collections.Generic;\r\nnamespace Wolf.Message\r\n{ \r\n public class Messages\r\n {\r\n";
28 foreach (string catage in Generator.Keys)
29 {
30 str += " public class "+catage + "\r\n { \r\n";
31 foreach (Wolf.MessageEntry entry in Generator[catage])
32 {
33 str += "\r\n /// <summary>" +
34 "\r\n ///" + entry.Description +
35 "\r\n /// </summary>" +
36 "\r\n public static Wolf.MessageEntry " + entry.Id + " = new MessageEntry(\"" + entry.Id + "\", \"" + entry.Value +"\", \"" + entry.Value +"\");\r\n";
37 }
38 str += "\r\n }\r\n\r\n";
39
40 }
41 str += "\r\n }\r\n}";
42 return str;
43 }
44
45 </script>
46 //Copyright (C) Wolf. All rights reserved.
47 <%= GeneratorCode()%>
48
49
很简单,就不说了,如果有问题请留言,其中命名空间完全可以以属性方式传入。
XMl实体用的是老A的:
2 <messages>
3 <message id="MandatoryField" value="The {0} is mandatory." category="Validation" description="description" />
4 <message id="GreaterThan" value="The {0} must be greater than {1}." category="Validation" description="description" />
5 <message id="ReallyDelete" value="Do you really want to delete the {0}." category="Confirmation" description="description" />
6 </messages>
7
8
我想脱离CodeSimth工具,所以在建立了一个控制台程序,引用CodeSmith.Engine.dll程序集。
Code:
2 {
3 // Wolf.Message.Messages.Confirmation.ReallyDelete.Value
4 // test();
5 CodeTemplate template = CompileTemplate(@"E:\MyApp\LinqTest\ConsoleApplication1\MessageCodeGenerator.cst",s=>Console.WriteLine(s));
6 if (template != null)
7 {
8 template.SetProperty("_MessageFilePath", "");
9 Wolf.MessageCodeGenerator gen = new MessageCodeGenerator();
10 Dictionary<string, List<MessageEntry>> dict = gen.GeneratorCode(@"E:\MyApp\LinqTest\ConsoleApplication1\Sample.xml");
11 template.SetProperty("Generator", dict);
12 template.RenderToFile("gen.cs", true);
13 // System.Diagnostics.Process.Start("gen.cs");
14 }
15 // Console.Read();
16
17 }
18
19 public static CodeTemplate CompileTemplate(string templateName,Action<string> errorWriter)
20 {
21 CodeTemplateCompiler compiler = new CodeTemplateCompiler(templateName);
22 compiler.Compile();
23
24 if (compiler.Errors.Count == 0)
25 {
26 return compiler.CreateInstance();
27 }
28 else
29 {
30 for (int i = 0; i < compiler.Errors.Count; i++)
31 {
32 errorWriter(compiler.Errors[i].ToString());
33 }
34 return null;
35 }
36
37 }
38
39
生成后的代码:
2 using Wolf;
3 using System;
4 using System.Collections.Generic;
5 namespace Wolf.Message
6 {
7 public class Messages
8 {
9 public class Validation
10 {
11
12 /// <summary>
13 ///description
14 /// </summary>
15 public static Wolf.MessageEntry MandatoryField = new MessageEntry("MandatoryField",
16
17 "The {0} is mandatory.", "The {0} is mandatory.");
18
19 /// <summary>
20 ///description
21 /// </summary>
22 public static Wolf.MessageEntry GreaterThan = new MessageEntry("GreaterThan",
23
24 "The {0} must be greater than {1}.", "The {0} must be greater than {1}.");
25
26 }
27
28 public class Confirmation
29 {
30
31 /// <summary>
32 ///description
33 /// </summary>
34 public static Wolf.MessageEntry ReallyDelete = new MessageEntry("ReallyDelete",
35
36 "Do you really want to delete the {0}.", "Do you really want to delete the {0}.");
37
38 }
39
40 }
41 }
42
43
ok,全部完成。同时你也可以完全集成与VS中利用VSX Vs扩展,可以参考明年我18 的VSX系列