代码改变世界

通过代码生成机制实现强类型编程-CodeSimth版

2010-09-25 09:23  破狼  阅读(4277)  评论(29编辑  收藏  举报

        一直想写一个Code生成系列,但写到CodeSimth,发觉在TerryLee努力学习的小熊 两位大牛的博客里讲很详尽,所以就像写些示例方面的,但是苦于没有想到写些什么。最近Artech写了两篇从数据到代码——通过代码生成机制实现强类型编程--上篇和下篇,大牛写得是CodeDom的,今天我就想借借大牛的示例写个CodeSimth版的,希望Artech不要怪我,呵呵。我的Code生成技术已经写了CodeDom的见CodeDom系列目录,欢迎各位园友指教。

        好直接到主题。首先是数据实体MessageEntry(我到老A的基础上添加了description属性作为代码字段描述):

 

代码
 1 namespace Wolf 
 2 
 3     public class MessageEntry 
 4     { 
 5         public string Id { getprivate set; } 
 6         public string Value { getprivate set; }        
 7         public string Description { getprivate 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:

 

代码
 1 using System; 
 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:

 

代码
 1 <%@ CodeTemplate Language="C#" TargetLanguage="Text" Src="" Inherits="" Debug="False" Description="Template description here." %> 
 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的:

 

代码
1 <?xml version="1.0" encoding="utf-8" ?>  
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:

 

代码
 1 static void Main(string[] args) 
 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 

 

 

生成后的代码:

 

代码
 1 //Copyright (C) Wolf.  All rights reserved. 
 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系列