最近课程要升级到5.0,其中有个叫做代码生成工具的东西,偷空看了一下,感觉还不错,因而写点东西以志纪念,废话完了。


读者水平:懂一点ASP.Net,会写三层架构,对程序员枯燥的生活有一定认识。


使用的工具:CodeSmith4.0,C#,NotePad,SqlServer2000或更高。


提要:CodeSmith是一款以大批量生成代码为目标的工具,可以生成的代码包括各种编程语言代码,以及各种标记语言的代码,CodeSmith是以解除程序员编写大量的,有规律的,重复性劳动为己任。


前提:


1.         良好的数据库设计:CodeSmith的工作需要从数据库中获得相当多的信息,良好的数据库设计可以使设计更简单。


2.         一种以上的设计模式:通俗的说就是,你知道代码应该怎么写。


3.         初步.Net语言基础:在CodeSmith中可以使用的语言为.Net支持的语言。


模板:CodeSmith生成代码的基础为数据库,生成代码依赖于你编写的模板。


模板分成三部分:声明,输出,函数。


声明部分包括CodeTemplate,Property,Assembly,Import,Register,Map,XmlProperty。


CodeTemplate声明:



































CodeTemplate声明的属性


Language


语言


编写输出和函数部分使用的语言 


TargetLanguage


目标语言


生成代码的语言 


Src


源文件


模板中使用的类文件名称 


Inherits


继承的类


模板继承自的类名 


Debug


调试


是否需要调试 


Description


描述


简介 


ResponseEncoding


输出编码格式


设置输出内容的编码格式 



 


CodeTemplate声明为必选声明。


Language:一般可以使用C#,VB,JScript等语言,此处要慎重,尽量选择熟悉的语言。


TargetLanguage:通过模板生成的代码的语言,一般来说,无关紧要,但还是尽量实事求是的写吧,因为CodeSmith需要这个属性来给代码着色。


Src和Inherits:这两个属性非常接近,都是我们要写的模板的父类,Src写的是源文件名称路径,Inherits写的是继承的父类名称。这两个属性可以不设置。


Debug:可选True或False,用来决定是否调试,简单模板一般设置为False。


ResponseEncoding:如果要让你的模板生成的内容中包括中文,那么设置这个属性为UTF-8。


比较典型的CodeTemplate声明如下:


<%@ CodeTemplate Language=”C#” TargetLanguage=”C#” Src=”” Inherits=”” Debug=”False” Description=”产生实体类” ResponseEncoding=”UTF-8″ %>


Property声明:































Property声明属性


Name


名称


类似变量名称


Type


类型


类似变量类型


Default


默认值


默认值


Optional


是否可选


Bool类型,True:可选,False:必选


Category


分组名称


 


Description


描述


 



Assembly声明:











Assembly声明属性


Name


名称


程序集名称,不包括.dll后缀



Assembley声明类似.Net工程中的引用程序集。


Import声明:











Import声明属性


Name


名称


命名空间



Import声明类似.Net工程中的使用命名空间,类似于using System;。


Register声明:















Register声明属性


Name


名称


将模板作为一个类的别名使用


Template


模板名称


模板文件的全路径



 


土鳖抗铁牛。


 


书接上回。


输出部分:这个部分的内容最终会到达最终生成的源代码文件,所以在编写这部分内容的时候,一定要对将要生成的内容的结构十分熟悉和了解。


在输出的部分可以使用在声明部分定义的Property声明的参数,其实可以将CodeSmith模板看做是一个返回值类型为String的函数,那么Property部分的内容就是这个函数的参数。


输出部分可以划分为两部分:




  1. 固定内容:指的是没有在<%%>中间包括的内容。


  2. 可变内容:在<%%>和<%=%>中间包括的内容

在<%%>中间可以填写的内容为:在模板声明部分的CodeTemplate声明中Language属性所指的语言编写的任何内容,可以定义变量,常量,可以使用各种控制结构,几乎是任何语句都可以,因为CodeSmith毕竟是架构在.Net体系结构中的。


做一个小例子:目的是从外界传入一个字符串参数,在模板中将这个字符串循环输出10次。


模板内容为:


<%@ CodeTemplate Language=”C#” TargetLanguage=”Text” Src=”” Inherits=”” Debug=”False” Description=”Template description here.” %>
<%@ Property Name=”TestString” Type=”System.String” Default=”SomeValue” Optional=”True” Category=”Strings” Description=”This is a sample string property.” %>
<%for(int i=0;i<10;i++)
{
 Response.WriteLine(“第”+i.ToString()+”次:”+TestString);
}
%>


这个模板编写的时候使用的语言为C#,而生成的内容为Text,当前模板有一个输入的参数:参数名称为TestString,类型为String,默认值为“SomeValue”,这个模板编译后,执行的结果为:


第0次:aaaaa
第1次:aaaaa
第2次:aaaaa
第3次:aaaaa
第4次:aaaaa
第5次:aaaaa
第6次:aaaaa
第7次:aaaaa
第8次:aaaaa
第9次:aaaaa


大家看到了在这里使用了循环结构和一个类Response,是不是很熟悉?哦,那…,对了,就是在Asp.Net中是不是有一个对象叫做Response,啥意思嘛?你知道的,不就是向客户端浏览器输出的对象么,当然了在这里会有点变化,不过不大,在CodeSmith中Response为输出的对象,这个对象借用了Response的壳子,它的魂却是控制台应用程序中常用的输出输入对象Console。


 接下来我们开始写这个模板的第二个版本,注意观察,当前模板中有一部分内容是从来都不变化的,找到它了吗?嗯,对了,就是“第”和“次:”这两个汉字,那么能不能不在循环中拼接字符串,这些内容可以直接输出呀。


<%for(int i=0;i<10;i++)%>
<%{%>
<%Response.Write(i);%>次:<%Response.Write(TestString);%>
<%}%>


这回我们将一个<%%>换成了多个,“第”和“次:”已经不在<%%>之内了,但是他们照样输出了,而且输出了10次,原因是第<%Response.Write(i);%>次:<%Response.Write(TestString);%>在了for循环的循环体之内,这就意味着我们可以将控制结构根据需要拆分在不同的<%%>之内,额外的好处是编写模板将会变得非常简单和非常灵活,有变化的内容写在<%%>之内,没有变化的内容,写在<%%>之外就可以了。


目前还是有点麻烦,因为每次输出都要写一遍Response.Write(),累,在Asp.Net中的<%%>之内有一个用法可以直接输出变量或常量的值:<%=变量名称%>或<%=常量名称%>(注意此处的<%=%>中没有“分号”),这样我们的简单模板就有了第三个版本了:


<%@ CodeTemplate Language=”C#” TargetLanguage=”Text” Src=”” Inherits=”” Debug=”False” Description=”Template description here.” %>
<%@ Property Name=”TestString” Type=”System.String” Default=”SomeValue” Optional=”True” Category=”Strings” Description=”This is a sample string property.” %>
<%for(int i=0;i<10;i++)%>
<%{%>
<%=i%><%=TestString%>
<%}%>


其实我们可以在模板的<%%>之内写任何代码,不过由于模板主要用来输出目标源代码,因而除了比较的控制结构和变量定义之外,甚少做其他的事情。


聪明的你是否已经想用模板来批量输出某些内容了吧,嗯,挺好的…,就这样,非常好…,继续保持啊…


请大家完成一个小作业:在Internet上有一个网站www.goodweb.com,这个网站上包括了很多精美的小说,这些小说的Url类似于书接上回。


作业做完了没?还没?来啊,拖出去,翻过来打。


函数部分:这部分可以放一些在输出部分使用的函数,函数当中也可以使用在声明部分定义的参数。


函数部分必须包括在<script runat=”template”><script>


什么?不知道函数是什么?啥叫重载?嗯…,这样给你个建议,请将鼠标移动到当前这个窗口的右上角,看到了那个×了没?点一下。欢迎你再来啊。


这回书完了。


就这么着就完了,你不是忽悠我吗。


给个例子嘛…


嗯,好的。



public int Sum(int x,int y)


{


    return x+y;


}




啊,就这?


啊,就这!


书接上回。


这回,我们开始探讨CodeSmith与数据库的联系,在CodeSmith中自带一个程序集SchemaExplorer.dll,这个程序集中的类主要用于获取数据库中各种对象的结构。


下面的图是SchemaExplorer中主要类的结构和功能:



这回书,我们利用SchemaExplorer中的类:TableSchema,ColumnSchema来制造一个实体类。


首先我们得了解实体类的构成,一般的实体类由私有字段和公开方法组成,例如下面的类:


using System;
using System.Collections.Generic;
using System.Text;


namespace com.xaccp.Entity
{
    public class Person
    {
        private string name;
        private bool sex;
        private int age;


        public string Name
        {
            get { return name; }
            set { name = value; }
        }


        public bool Sex
        {
            get { return sex; }
            set { sex = value; }
        }


        public int Age
        {
            get { return age; }
            set { age = value; }
        }
    }
}


实体类中的字段应该和数据库中的字段相同,只是类型要从Sql中的数据类型变为C#中的数据类型,一般实体类中的字段的名字可以采用与数据库中字段的名称相同,只不过字段名一般采用骆驼命名法,属性名称一般采用Pascal命名法。


私有字段部分有些内容是永远不变的,字段的访问修饰符永远为“private”,字段的结尾永远为“;”;变化的部分为,每个字段根据数据库中的类型变化为C#中的类型,字段的名称也是变化的。


公开字段中也有内容为永远不变的,        public 数据类型 属性名称
        {
            get { return 字段名称; }
            set { 字段名称 = value; }
        }


只要我们能够获得某个表中字段名称,字段类型,那么就可以生成实体类的内容部分。


从上回书中,我们了解到,TableSchema可以获得某个表中所有的列的信息。下面我们来写我们的第一个模板。


<%@ CodeTemplate Language=”C#” TargetLanguage=”C#” Src=”” Inherits=”” Debug=”False” Description=”产生实体类” ResponseEncoding=”UTF-8″ %>
<%@ Property Name=”SourceTable” Type=”SchemaExplorer.TableSchema” Default=”” Optional=”False” Category=”Context” Description=”源表” %>
<%@ Assembly Name=”SchemaExplorer” %>
<%@ Import Namespace=”SchemaExplorer” %>
<%@ Assembly Name=”System.Data” %>
<%@ Import Namespace=”System.Data” %>


using System;


namespace com.xaccp.Entity
{
    public class Person
    {
        //这里的内容为私有字段和公开属性。
  <%foreach(ColumnSchema column in this.SourceTable.Columns)%>
  <%{%>
  private <%=column.SystemType%> <%=column.Name%>;
  <%}%>
  <%foreach(ColumnSchema column in this.SourceTable.Columns)%>
  <%{%>
  public <%=column.SystemType%> <%=column.Name%>
  {
   get{return <%=column.Name%>;}
   set{<%=column.Name%>=value;}
  }
  <%}%>
    }
}

Comments are closed.

Post Navigation