最近因项目需要学习了一下CodeSmith。CodeSmith是一个基于模板的代码生成工具,可以用它来快速生成代码,减少项目编码中的重复劳动。
我们可以在CodeSmith中制定模板(当然这些模板是可以重复使用的),然后输入一些参数,最后生成所需的代码脚本。这就是CodeSmith大体的工作流程啦。
我认为CodeSmith最核心的思想是将一个代码文件中的内容分解成几个部分,即:
固定不变的内容(Content that will never change);
可自动产生的内容(Content that can be automatically generated);
可让用户指定的内容(Content that you will prompt the user for)。
固定不变的内容主要是由一些固定格式的声明、定义和特定的方法调用,这些内容构成我们模板的大体结构。
可自动产生的内容主要是一些在代码生成时能自动产生的信息,如代码生成日期,这些信息我么可以通过调用方法来获得。
可让用户指定的内容则是由模板得到最终代码所需的一些参数,不同的参数导致由同一模板生成不同的实际代码,是从抽象到具体的桥梁。
下面一个简单的例子说明了以上三点。
<%--
Name: HelloWorldTemplate
Author: Aixe
Description: The
is
a simple template to help learn CodeSmith.
--%>
<%
@ CodeTemplate Language
=
"
C#
"
TargetLanguage
=
"
C#
"
Description
=
"
A simple template for Hello World program.
"
%>
<%
@ Property Name
=
"
NamespaceName
"
Type
=
"
System.String
"
Default
=
"
HelloWorld
"
Optional
=
"
False
"
Category
=
"
Context
"
Description
=
"
A name for your namespace.
"
%>
<%
@ Property Name
=
"
ClassName
"
Type
=
"
System.String
"
Default
=
"
Program
"
Optional
=
"
False
"
Category
=
"
Context
"
Description
=
"
A name for your class.
"
%>
<%
@ Property Name
=
"
ClassAccessibility
"
Type
=
"
AccessibilityEnum
"
Optional
=
"
True
"
Category
=
"
Context
"
Description
=
"
The accessibility of your class.
"
%>
<%
@ Property Name
=
"
Author
"
Type
=
"
System.String
"
Optional
=
"
False
"
Category
=
"
Customized
"
Description
=
"
Your name here.
"
%>
<%
@ Property Name
=
"
Words
"
Type
=
"
System.String
"
Default
=
"
Hello World!
"
Optional
=
"
False
"
Category
=
"
Content
"
Description
=
"
Words to say.
"
%>
<%
@ Assembly Name
=
"
System.Data
"
%>
<%
@ Import Namespace
=
"
System
"
%>
//
This code is writen by: <%= Author %>
//
Create at: <%= DateTime.Now.ToString("yyyy-MM-dd hh:mm:ss") %>
using
System;
namespace
<%=
NamespaceName
%>
{
<%=
GetAccessibility()
%>
class
<%=
ClassName
%>
{
static
void
Main(
string
[] args)
{
Console.WriteLine(
"
<%= Words %>
"
);
Greeting(
"
<%= Author %>
"
);
}
static
void
Greeting(
string
name)
{
Console.WriteLine(
string
.Format(
"
Hello, {0}
"
, name));
}
}
}
<
script runat
=
"
template
"
>
public
enum
AccessibilityEnum
{
Public,
Protected,
Private,
}
public
string
GetAccessibility()
{
switch
(ClassAccessibility)
{
case
AccessibilityEnum.Public:
return
"
public
"
;
case
AccessibilityEnum.Protected:
return
"
protected
"
;
case
AccessibilityEnum.Private:
return
"
private
"
;
default
:
return
string
.Empty;
}
}
</
script
>
整个模板大致分为3个部分:模板和属性声明,模板主体和脚本。
每个模板前面都有一个声明语句,标明模板使用的语言和目标语言:
<%
@ CodeTemplate Language
=
"
C#
"
TargetLanguage
=
"
C#
"
Description
=
"
A simple template for Hello World program.
"
%>
接下来声明了模板中用到的几个属性,分别是命名空间的名字(NamespaceName),类名(ClassName),类的访问类型(ClassAccessibility),这是一个枚举类型,在后面的脚本中有定义,作者(Author)和一句信息(Words)。这些信息都由用户自己来输入的。这里的一些属性给出了默认值。
<%
@ Property Name
=
"
NamespaceName
"
Type
=
"
System.String
"
Default
=
"
HelloWorld
"
Optional
=
"
False
"
Category
=
"
Context
"
Description
=
"
A name for your namespace.
"
%>
<%
@ Property Name
=
"
ClassName
"
Type
=
"
System.String
"
Default
=
"
Program
"
Optional
=
"
False
"
Category
=
"
Context
"
Description
=
"
A name for your class.
"
%>
<%
@ Property Name
=
"
ClassAccessibility
"
Type
=
"
AccessibilityEnum
"
Optional
=
"
True
"
Category
=
"
Context
"
Description
=
"
The accessibility of your class.
"
%>
<%
@ Property Name
=
"
Author
"
Type
=
"
System.String
"
Optional
=
"
False
"
Category
=
"
Customized
"
Description
=
"
Your name here.
"
%>
<%
@ Property Name
=
"
Words
"
Type
=
"
System.String
"
Default
=
"
Hello World!
"
Optional
=
"
False
"
Category
=
"
Content
"
Description
=
"
Words to say.
"
%>
接下来定义代码的模板主体,这里的内容大多是不变的,需要变动的地方就通过嵌入一段代码来得到动态的内容。
其中namespace的名字使用的是NamespaceName这个属性的值,类名用的是ClassName的值,通过调用GetAccessibility()方法得到类的访问属性。这些属性值是用户来指定的。不难发现,其写法很像ASP.NET中的数据绑定。
注释中的Create at一句则是通过调用System.DateTime.Now来获得代码创建的时间,属于自动生成的部分。
//
This code is writen by: <%= Author %>
//
Create at: <%= DateTime.Now.ToString("yyyy-MM-dd hh:mm:ss") %>
using
System;
namespace
<%=
NamespaceName
%>
{
<%=
GetAccessibility()
%>
class
<%=
ClassName
%>
{
static
void
Main(
string
[] args)
{
Console.WriteLine(
"
<%= Words %>
"
);
Greeting(
"
<%= Author %>
"
);
}
static
void
Greeting(
string
name)
{
Console.WriteLine(
string
.Format(
"
Hello, {0}
"
, name));
}
}
}
我们在定义ClassAccessibility这个属性时,使用了自定义的枚举类型AccessibilityEnum,因此还要在脚本中声明之。另外由于public, protected和,private是C#里的关键字,所以枚举里面的首字母P不能小写。为了根据ClassAccessibility属性的值获得类的访问属性,还需编写GetAccessibility()方法。
<
script runat
=
"
template
"
>
public
enum
AccessibilityEnum
{
Public,
Protected,
Private,
}
public
string
GetAccessibility()
{
switch
(ClassAccessibility)
{
case
AccessibilityEnum.Public:
return
"
public
"
;
case
AccessibilityEnum.Protected:
return
"
protected
"
;
case
AccessibilityEnum.Private:
return
"
private
"
;
default
:
return
string
.Empty;
}
}
</
script
>
完成以上步骤后,一个简单的模板就做好了。编译之后,可在属性面板里看到我们自定义的属性在这里被列了出来:
输入Author属性再运行,就可得到我们需要的代码了。
//
This code is writen by: Aixe
//
Create at: 2009-08-02 10:52:24
using
System;
namespace
HelloWorld
{
public
class
Program
{
static
void
Main(
string
[] args)
{
Console.WriteLine(
"
Hello World!
"
);
Greeting(
"
Aixe
"
);
}
static
void
Greeting(
string
name)
{
Console.WriteLine(
string
.Format(
"
Hello, {0}
"
, name));
}
}
}
更改属性之后可以生成不同的代码。
可以看出,写CodeSmith模板和写ASP.NET很类似,熟悉的同学应该能很快上手。以上就是对CodeSmith的一次小小的体验,当然CodeSmith还有很多强大的功能和用法,CodeSmith本身也为我们提供许多很有用的模板供我们学习和使用,具体可以参考CodeSmith的帮助文档或网上的一些资料。