CodeSmith学习笔记

最近因项目需要学习了一下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";
        
defaultreturn 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";
        
defaultreturn 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的帮助文档或网上的一些资料。

posted on 2009-08-02 10:59  John Smith  阅读(596)  评论(1编辑  收藏  举报