CodeSmith是一个模仿asp.net运行机制的代码生成器, 运行时分析模板(相当aspx文件)的预编译指令和主体内容, 生成一个继承自CodeSmith.Engine.CodeTemplate(相当于System.Web.UI.Page)或者一个在Inherites预编译指令指定的类(相当于CodeBehind类)的源码, 且把它编译. 然后把这个类绑定到一个PropertyGrid, 让用户编辑参数后执行生成类的__RenderMethod1(相当于Render)方法生成最终代码. 这种模式很好的把易变的生成内容和相对稳定的用于的生成代码的数据源隔离开来.
我认识的大多数CodeSmith用户都是根据数据库结构去生成实体类, 存储过程或者asp.net的界面, 而CodeSmith本身提供了SchemaExplorer用于读取数据库结构, 在模板的预编译指令声明类型为SchemaExplorer.TableSchema的属性即可使用. 而大多数模板都是利用SchemaExplorer去获得数据库结构.
PropertyGrid是用户和根据模板生成的类之间互动的桥梁, 通过在属性或者属性所属类型上标记EditorAttribute可以任意扩展该属性在PropertyGrid里的表现形式, 详细情况请参考http://www.microsoft.com/china/msdn/archives/library/dndotnet/html/usingpropgrid.asp
然而CodeSmith并不支持在模板里定义的属性标记Attribute, 即使有, 在CodeSmithStudio里写这么复杂的代码也不方便. 解决方法就是自己在vs.net写一个模板的基类(必须从CodeSmith.Engine.CodeTemplate继承), 然后通过指定Inherites关键字让模板从基类继承, 这时就可以利用EditorAttribute为所欲为了. 我做了一个可以用来生成多个nhibernate实体类, xml映射和aspx界面的模板基类, 还可以把填写的内容序列化到xml文件和从xml文件反序列化. 我并没有用TableSchema去做生成代码的数据源, 而是有自定义的数据结构, 并且可以手工用XtraGrid去编辑, 当然也可以利用SchemaExplorer去从数据库取结构. 这个基类的结构如下:
| ◆-------> 0 * |
| ◆-------> 0 * |
|
ClassGenerator还有3个特殊属性SelectedClasses, Save, Load. 它们没有任何意义, 只是利用它们标记的EditorAttribute执行用SchemaExplorer一次选择多个表, 把编辑的内容保存成xml和从xml加载的功能
源码及模板
btw: 我用XtraGrid时遇到问题, 删除一列时被选中列就会往后跳一条, 结果就是删到倒数第二条时会出现索引超出范围的错误, 谁知道怎么解决?