最近课程要升级到5.0,其中有个叫做代码生成工具的东西,偷空看了一下,感觉还不错,因而写点东西以志纪念,废话完了。
读者水平:懂一点ASP.Net,会写三层架构,对程序员枯燥的生活有一定认识。
使用的工具:CodeSmith4.0,C#,NotePad,SqlServer2000或更高。
提要:CodeSmith是一款以大批量生成代码为目标的工具,可以生成的代码包括各种编程语言代码,以及各种标记语言的代码,CodeSmith是以解除程序员编写大量的,有规律的,重复性劳动为己任。
前提:
1.
2.
3.
模板: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部分的内容就是这个函数的参数。
输出部分可以划分为两部分:
固定内容:指的是没有在<%%>中间包括的内容。
可变内容:在<%%>和<%=%>中间包括的内容
在<%%>中间可以填写的内容为:在模板声明部分的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++)
{
}
%>
这个模板编写的时候使用的语言为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)
{
}
啊,就这?
啊,就这!
书接上回。
这回,我们开始探讨CodeSmith与数据库的联系,在CodeSmith中自带一个程序集SchemaExplorer.dll,这个程序集中的类主要用于获取数据库中各种对象的结构。
下面的图是SchemaExplorer中主要类的结构和功能:
这回书,我们利用SchemaExplorer中的类:TableSchema,ColumnSchema来制造一个实体类。
首先我们得了解实体类的构成,一般的实体类由私有字段和公开方法组成,例如下面的类:
using System;
using System.Collections.Generic;
using System.Text;
namespace com.xaccp.Entity
{
}
实体类中的字段应该和数据库中的字段相同,只是类型要从Sql中的数据类型变为C#中的数据类型,一般实体类中的字段的名字可以采用与数据库中字段的名称相同,只不过字段名一般采用骆驼命名法,属性名称一般采用Pascal命名法。
私有字段部分有些内容是永远不变的,字段的访问修饰符永远为“private”,字段的结尾永远为“;”;变化的部分为,每个字段根据数据库中的类型变化为C#中的类型,字段的名称也是变化的。
公开字段中也有内容为永远不变的,
只要我们能够获得某个表中字段名称,字段类型,那么就可以生成实体类的内容部分。
从上回书中,我们了解到,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
{
}