今天进入ORM工具开发系列的代码生成工具的开发。现在流行的代码生成工具,一般是基于模板的。T4,Code Smith在基于模板的代码生成方面相当流行。ORM工具,需要从不同的数据库中读取元数据,调用代码生成模板,生成代码。

先来看一下代码生成器的界面,边看边说。

界面是采用文章《Management Console 工具管理类软件通用开发框架(开放源码)》中提到的代码框架,加上停靠的Output窗口,输出编译错误和调试信息,Properties窗体,用于解析属性,设置属性值,Server Explorer用来连接数据库获取元数据,调用代码生成模板。

文件格式

模板的文件的第一种格式是《Write your own Code Generator or Template Engine in .NET》中提到的技术,把引用的程序集,和引用的命名空间,都放到文件中。这样,文件肯定不能是文本格式的,它是模板对象的Xml序列化格式。

Input是模板的内容,References引用的程序集。Using_Libraries是导入命名空间,C#为using,VB.NET是Import。

这种格式,在开始开发模板生成器时,我采用这种格式。但是,后来发现效率不好,每次打开和关闭文件时,都需要序列化为Base64编码,这需要耗费时间,另外,这种格式不支持Notepad来编辑,不是纯文件,不方便编辑。

经过对第一种格式的改良,学习Code Smith格式模板的格式,采用文本格式作为模板文件的格式。看起来是这样

<%@ Assembly Name="TestClassLibrary" %>
<%@ Import Namespace="EPN.Common" %>

public class Jack
{
    public void Main()
    {
        int key=System.Console.ReadKey();
    }
}

这样,将引用的程序集和导入的命名空间,放到模板中。这样,简化了模板的写法,但是,会增加很多编译的设置工作。

模板语法

模板生成器的基本原理是,将模板生成为一个类型,调用它生成的程序集的代码,输入结果。根据接触到的LLBL Gen 3.x的模板语法和Code Smith的模板语法,ASP.NET的Page页面文件,模板的语法看起来是这样

<%@ Property Name="IncludeDrop" Type="System.Boolean" Default="True" Category="Options" Description="If true drop statements will be generated to drop existing stored procedures." %>
<%@ Assembly Name="System.Data" %>
<%@ Import Namespace="System.Data" %>

<%
string property1= "DemoClass";

%>
Current DateTime is: <%=DateTime.Now%>
Test Property :<%=IncludeDrop%>
<% for(int i=0;i<10;i++) { %>
         <%=Math.ApplictionName%> <%=i%>
        <% } %>

这里取自于Code Smith的语法。我写的这个Template Studio也可以解析有Code Smith的模板,语法与之相似。

Property 标签用来定义属性,以便接受用户的输入,应用到模板中。这个值,在解析模板时,会解析有成为类型的变量,以便于使用。 这里有支持三种类型的属性,Boolean,String,Int32。语法如下所示

<%@ Property Name="IncludeInsert" Type="System.Boolean" Default="True" Category="Options" Description="If true insert statements will be generated." %>
<%@ Property Name="IncludeUpdate" Type="System.String" Default="CNBLOGS" Category="Options" Description="If true update statements will be generated." %>
<%@ Property Name="IncludeDelete" Type="System.Int32" Default="123" Category="Options" Description="If true delete statements will be generated." %>

这样说可能还不太明白,请看一下面的图

解析引擎会分析到模板有三个参数,会在右边的Properties窗体中显示出来,并且提供值,让用户重新输入,这样达到动态变量的目的。在运行模板时,会把这个值传到模板生成的代码中去。

再来看,如何定义类型变量,而不是简单类型。模板举例如下

<%@ Property Name="Math" Type="MathProgram"  Category="Text"Description="Namespace for this class" %>

<%@ Assembly Name="TestClassLibrary" %>
<%@ Import Namespace="EPN.Common" %>

public class Jack
{
    public void Main()
    {
        int key=System.Console.ReadKey();
       <%=Math.SystemName%>
        <% for(int i=0;i<10;i++) { %>
         <%=Math.ApplictionName%> <%=i%>
        <% } %>
    }
}

和添加普通的简单类型变量一样,MathProgram是类型名称,Math是属性名,因为是类型,所以加上Assembly以指明类型所在的程序集,Import指明类型所在的命名空间,这两个值可以唯一确定一个类型。

来看类型MathProgram的定义,

[TypeConverter(typeof(ExpandConverter))]
public class MathProgram
{
      public MathProgram(string system,string application)
      {
          _SystemName = system;
          _ApplictionName = application;
      }

public MathProgram(){}

private string _SystemName;
      [Browsable(true)]
      [Category("Text")]
      [DefaultValue("")]
      [Description("Namespace for this class")]
      public string SystemName
      {
          get { return _SystemName; }
          set { _SystemName = value; }
      }

private string _ApplictionName;

[Browsable(true)]
      [Category("Text")]
      [DefaultValue("")]
      [Description("Namespace for this class")]
      public string ApplictionName
      {
          get { return _ApplictionName; }
          set { _ApplictionName = value; }
      }

}

解析后的效果是这样

为什么要这么定义? 我来简化一下它的写法,本来是可以这样写的,我初始的想法是这样的版本

public class MathProgram
{
      public MathProgram(string system,string application)
      {
          _SystemName = system;
          _ApplictionName = application;
      }

public string _ApplictionName;

public string _SystemName;

}

PropertyGrid控件,不认识变量成员定义,只认识属性,Refactor—>Encapsulate Field变成属性。
还要加上[Browsable(true)],以指示在PropertyGrid控件中显示,[Category("Text")]是解析自它的属性声明,
[DefaultValue("")]和[Description("Namespace for this class")]也是一样的原理。

MathProgram的定义还加上了声明式的特性[TypeConverter(typeof(ExpandConverter))],目的是为了在PropertyGrid中展开显示,如果没有这个特性,它在PropertyGrid中是只读的,显示为灰色。

最后要提到的模板语法内容,是ASP.NET样式的代码片段,像这样

<% for(int i=0;i<10;i++) { %>
         <%=Math.ApplictionName%> <%=i%>
        <% } %>

<%和%>之间的代码,会原封不动的Render到生成的类型中,以用于解析成可执行的代码。

与.NET属性窗口交互的RAD组件

属性的解析,生成,获取用户输入的属性值,是模板生成器的一项重要的工作。先看这个例子

上面解析到Properties窗体中的代码,下面的代码解释它的工作原理

MathProgram builder = new MathProgram();
builder.ApplicationName= "Template Studio";
builder.SystemName= " ORM";
propertyGrid1.SelectedObject = builder;

ApplicationName和SystemName是Encapsulate Field的属性名称,并且带有Browsable,Category元数据。

如果把这个类型放到另一个类型中去,代码像这样

Builder builder = new Builder();
builder.Category = "CNBLOGS";
builder.Math = new MathProgram();
builder.Math.ApplicationName= "Template Studio";
builder.Math.SystemName=" ORM";
propertyGrid1.SelectedObject = builder;

为了能在Properties窗体中设置值,要给它写TypeConverter。一般像这样的公共代码就可以达到目的

public class CommonConverter : TypeConverter
{

public override PropertyDescriptorCollection
           GetProperties(ITypeDescriptorContext context,
                object value,
                Attribute[] filter)
       {
           return TypeDescriptor.GetProperties(value, filter);
       }

public override bool GetPropertiesSupported(
                ITypeDescriptorContext context)
       {
           return true;
       }
}

上一节中应用到的ExpandConverter类型转换器,它多了一项处理是可以把MathProgram显示为字符串,比如从”ORM,Template Studio”中解析成MathProgram对象,这是TypeConverter的功劳。

动态编译

模板的生成过程,就是生成一个以模板名字为类型名称,以模板代码为嵌入方法的过程。在代码过程中,大部分的代码都是在构造这个类型,以便于编译器编译成为程序集,再调用它的Render方法。方法代码如下

Assembly assembly=CreateAssembly(sourceTemplate,language,parameters);

Type  type=assembly.GetType(“Template”);

InvokeMethod(type,”Render”);

把这三个过程细化,就是模板代码生成的原理。在《模板代码生成的原型》一节,再详细讲解动态编译。

转载于:https://www.cnblogs.com/JamesLi2015/archive/2011/09/05/2167000.html

ORM框架-工具-产品开发之四 开发代码生成器 Template Studio Development (一)相关推荐

  1. orm框架设计、分析与开发

    orm框架设计.分析与开发 前面写过几篇文章介绍和分析mybatis,今天拆解下要设计一个ORM框架涉及到哪些方面,如何用现有的一些已知工具像spring jdbc.freemarker等重新造一个O ...

  2. Orm框架介绍和常见的Android Orm框架

    ORM(Object Relational Mapping)框架采用元数据来描述对象一关系映射细节,元数据一般采用XML格式,并且存放在专门的对象一映射文件中. 先介绍一下ORM的概念,以前也一直听说 ...

  3. 论ORM框架—EntityFrameworkCore

    欢迎大家阅读<朝夕Net社区技术专刊> 我们致力于.NetCore的推广和落地,为更好的帮助大家学习,方便分享干货,特创此刊!很高兴你能成为忠实读者,文末福利不要错过哦! 01 PART ...

  4. 流行的ORM框架简介

    摘自 李刚 著<Java EE企业级应用实战> 目前ORM框架的产品非常之多,除了个大公司.组织的产品外,其他一些小团队也在推出自己的ORM框架.目前流行的ORM框架有如下这些产品: (1 ...

  5. 技能学习:学习使用php(tp6框架) + vue.js,开发前端全栈网站-1.工具和本地环境

    技能学习:学习使用php(tp6框架) + vue.js,开发前端全栈网站-1.工具和本地环境 技能学习:学习使用php(tp6框架) + vue.js,开发前端全栈网站-1.工具和本地环境 技能学习 ...

  6. RF框架(二)_ 开发工具RIDE介绍

    一.Robot Framework介绍 RF官网:https://robotframework.org/ Robot Framework是通用的开源自动化框架.它可以用于测试自动化和Robot过程自动 ...

  7. ORM框架-VB/C#.Net实体代码生成工具(EntitysCodeGenerate)【ECG】4.6

    摘要:VB/C#.Net实体代码生成工具(EntitysCodeGenerate)[ECG]是一款专门为.Net数据库程序开发量身定做的(ORM框架)代码生成工具,所生成的程序代码基于OO.ADO.N ...

  8. ORM框架-VB/C#.Net实体代码生成工具(EntitysCodeGenerate)【ECG】4.5

    引言 内容 ORM框架的实现VBCNet实体代码生成工具EntitysCodeGenerate 在开发中的实际应用 结束语 相关下载地址 摘要:VB/C#.Net实体代码生成工具(EntitysCod ...

  9. 有哪些工具可以让嵌入式开发事半功倍?详细盘点工程师必备工具

    嵌入式开发就是指在嵌入式操作系统下进行开发,一般常用的系统有μcos,vxworks,linux,android等.当然,对于嵌入式或单片机工程师的利器就是C语言.C++或汇编语言.那么有哪些好工具可 ...

最新文章

  1. python 压缩图片
  2. 【设计模式】策略模式 ( 简介 | 适用场景 | 优缺点 | 代码示例 )
  3. 【两行命令】R语言读取excel数据
  4. RNN以及LSTM的介绍和公式梳理
  5. mysql 回滚段 表空间_oracle回滚段和回滚表空间
  6. 【Linux】一步一步学Linux——reset命令(268)
  7. JavaScript学习笔记(一)—— 数据类型
  8. JS倒计时:从某个固定时间开始倒记
  9. 抓包测试步骤XMind
  10. centos7.4下的KVM虚拟机安装使用
  11. 前端 禁止微信调整字体大小
  12. UnitySDK新接入记录
  13. Android 小红点 未读消息功能 BadgeHelper
  14. 最落魄的日子你是怎样熬过来的
  15. idea删除文件时出现选项 “Safe delete ( with usage search)“ 和 “Search in comments and strings“
  16. 拼接大屏数据展示_大屏拼接可视化
  17. ADC相关参数之---INL和DNL
  18. Windows 连接了网络浏览器不能上网
  19. 汇编语言clr c什么意思,汇编程序中C(1):errorC129:missing';'before Bit是什么意思,加了分号也不对,怎么回事啊...
  20. mybatis拦截器实现update之前根据pk字段校验数据有效性

热门文章

  1. 什么是野指针和内存泄露?如何避免野指针
  2. CNN 神经网络tricks 学习总结
  3. scala使用zip合并两个集合为二元组集合
  4. 基于内容推荐系统中的常识
  5. Elasticsearch的Scroll操作
  6. Tomcat源码解析系列二:Tomcat总体架构
  7. VS Code 快捷键使用小技巧
  8. kdump和crash的配置方法与内核故障原因分析(一)
  9. android图像处理系列之五-- 给图片添加边框(中)
  10. GitStats:Git开发历史统计工具 - liyropt - 博客园