CodeSmith(2):对象和控制台

来源:互联网 发布:什么软件打开pdf 编辑:程序博客网 时间:2024/04/29 00:30

CodeSmith对象 

代码模板对象(CodeTemplate Object)

在模板中,this(或者Me在VB.NET中)在当前模板中代码代码模板对象。

 

代码模板的方法(CodeTemplate Methods)

1.public virtual void GetFileName()

可以重载这个方法设置模板输出到文件的名称。否则CodeSmith将基于模板名称和TargetLanguage设置它的文件名。

 

2.public void CopyPropertiesTo(CodeTemplate target)

这个方法可以实现从一个模板中将其所有属性的值拷贝到另一个模板所有对应属性中,并按照相应的属性值类型进行匹配。

 

3.public object GetProperty(string propertyName)

这个方法将返回一个给定名称的属性的值。

 

4.public void SetProperty(string propertyName, object value)

此方法可以根据给定名称的属性设置其值。

 

5.public string SavePropertiesToXml()

这个方法将现有的属性值保存成一个XML的属性字符串。

 

6.public void SavePropertiesToXmlFile(string fileName)

这个方法将当前属性值保存成一个XML的属性文件。

 

7.public void RestorePropertiesFromXml(string propertySetXml, string baseDirectory)

从保存在XML文件中的属性字符串,将模板的属性值恢复。

 

8.public void RestorePropertiesFromXmlFile(string fileName)

从保存在XML文件中的属性文件,将模板的属性值恢复。

 

代码模板的属性(CodeTemplate Properties)

Response:此属性可以访问当前的TextWriter对象,这个对象是用来输出模板用的。

 

CodeTemplateInfo:这个属性用来访问当前的CodeTemplateInfo对象,这个对象包含当前模板的一些信息。

CodeBehind Gets the full path to the code-behind file for the template (or an empty string if there is no code-behind file).

ContentHashCode Gets the hash code based on the template content and all template dependencies.  

DateCreated Gets the date the template was created.

DateModified Gets the date the template was modified.  

Description 说明信息

DirectoryName 全路径加文件加

FileName 模板文件名

FullPath 全路径  

Language 语言  

TargetLanguage 生成代码的语言 

:Response.WriteLine(this.CodeTemplateInfo.FileName) CodeTemplateInfo.cst

 

 

Progress:这个属性用来报告当前模板的执行过程。

 

Response Object

这个对象提供直接写输出模板的方法。与ASP.NET的response对象很相似。下面是一个利用Response的Write方法在模板上输出一段文字的例子。

 

<% Response.Write("This will appear in the template") %>

 

IndentLevel (Int32)

当使用Response对象时输出文本的缩进级别。

 

Indent() Method

将输出缩进一个级别。

 

Unindent() Method

将输出少缩进一个级别。

 

AddTextWriter(TextWriter writer) Method

为Response对象增加一个TextWriter。这样可以使在同一时间用多个TextWriter输出模板。

 

CodeTemplateInfo Object

此对象包含一些当前模板的信息。下面是一些CodeTemplateInfo可用的属性。

 

DateCreated (DateTime)

返回一个date类型值,是模板创建的时间。

 

DateModified (DateTime)

返回模板最后一次被修改的时间。

 

Description (string)

返回模板声明时对模版的描述信息。

 

DirectoryName (string)

返回当前模板文件所在的路径。

 

FileName (string)

返回当前模版文件的文件名称。

 

FullPath (string)

返回当前模板的完整路径,路径名+文件名。

 

Language (string)

返回代码模版声明时使用的语言。

 

TargetLanguage (string)

返回代码模版声明时生成的目标语言。

 

Progress Object

这个属性用来报告当前模板的执行过程。下面是一些Progress可用的成员。

使用Progress和在WinForm中使用进度条差不多,需要设置它的最大值和步长:

 

MaximumValue (Int32) 模版progress允许的最大值。

 

MinimumValue (Int32) 模版progress允许的最小值。

 

Step (Int32) 模版每执行一不progress的增长值。

 

Value (Int32) Progress的当前值。

 

PerformStep() Method按照指定好的progress的增加值执行一步。(原文:Perform a progress step incrementing the progress value by the amount specified in the Step property.)

 

Increment(Int32 amount) Method 指定progress的增加值。原文:Increment the progress value by the specified amount.)

 

OnProgress (ProgressEventHandler) Event 这个事件用来报告模版的执行过程。原文:This event can be used to be notified of template execution progress.)

this.Progress.MaximumValue = 25;

this.Progress.Step = 1;

如果想显示出进度需要调用PerformStep方法

this.Progress.PerformStep();

 

StringCollection

StringCollection提供了一种集合的输入方式在代码中可以用Array的方式来引用。在使用这个类之前,在模版中我们必须添加对CodeSmith.CustomProperties程序集的引用:

<%@ Assembly Name="CodeSmith.CustomProperties" %>

添加完程序集之后,我们就可以使用StringCollection在脚本块中定义一个属性:

<%@ Property Name="List" Type="CodeSmith.CustomProperties.StringCollection" Category="Custom" Description="This is a sample StringCollection" %>

执行该模版时,这个属性将在属性窗体中显示为一个按钮:

单击按钮,将会弹出一个String Collection Editor对话框:

 

当然也可以直接在属性窗口中编辑StringCollection

模版代码如下:

<%for(int i = 0;i<List.Count;i++){%>

      Console.WriteLine(<%=List[i]%>);

 <%}%>

公共属性

Count  获取StringCollection中包含的字符串的数目

IsReadOnly  获取用于指示StringCollection是否为只读的值

IsSynchronized  获取一个值,该值指示对StringCollection 的访问是否为同步的(线程安全的)

Item  获取或设置指定索引处的元素。在C# 中,该属性为 StringCollection 类的索引器

SyncRoot  获取可用于同步对StringCollection 的访问的对象

公共方法

Add  将字符串添加到 StringCollection 的末尾

AddRange  将字符串数组的元素复制到 StringCollection 的末尾

Clear  移除 StringCollection 中的所有字符串

Contains  确定指定的字符串是否在 StringCollection

CopyTo  从目标数组的指定索引处开始将全部 StringCollection 值复制到一维字符串数组中

IndexOf  搜索指定的字符串并返回 StringCollection 内的第一个匹配项的从零开始的索引

Insert  将字符串插入 StringCollection 中的指定索引处

Remove  StringCollection 中移除特定字符串的第一个匹配项

RemoveAt  移除 StringCollection 的指定索引处的字符串

 

CodeSmith控制台指南

 

很多人仅仅知道CodeSmith像一个图形应用程序或者可能是一个Visual Studio的附件但是通过CodeSmith的控制台应用程序还有好多其他的使用方法。控制台应用程序是很有价值的,因为可以通过它去生成脚本,或者其他一些自动工具。这篇文档的目的就是要告诉你怎样使用它的控制台应用程序并且如何去定义变量和参数。

 

Basic Usage

大多数情况下是用控制台应用程序来创建一个模板,一个属性文件,然后保存输出的文件。这有一个很好的例子介绍将合并模版的处理过程放到一个过程中,就像使用NAnt工具。

 

首先我们要确定完成一个什么样的模版,为这个模板创建一个什么样的XML属性文件。XML属性文件提供在执行模版是需要的各个属性。生成一个属性文件最简单的方法是在CodeSmith Explorer中打开一个模版,填写属性,点击生成按钮generate,然后再点击Save Property Set XML按钮。这个按钮会在点击完生成按钮后找到,在Save OutputCopy Output按钮旁边。然后系统提示输入保存XML属性文件的文件名,下面看一个ArrayList.cst模版创建的XML属性文件。

 

 1<?xml version="1.0" encoding="us-ascii"?>

 2<codeSmith>

 3            <propertySet>

 4                        <property name="Accessibility">Public</property>

 5                        <property name="ClassName">PersonArray</property>

 6                        <property name="ItemType">Person</property>

 7                        <property name="ItemValueType">False</property>

 8                        <property name="ItemCustomSearch">False</property>

 9                        <property name="KeyName">PersonID</property>

10                        <property name="KeyType">int</property>

11                        <property name="IncludeInterfaces">True</property>

12                        <property name="IncludeNamespaces">False</property>

13            </propertySet>

14</codeSmith>

 

就像看到的一样也可以手动创建这个文件但是使用CodeSmith Explorer会更简便。

现在我们有了这个XML文件,我们继续看一下如何去执行这个模版并是用控制台工具保存结果。首先我们需要是用/template参数去声明我们要是用的模版,像这样:

 

C:"Program Files"CodeSmith"v3.0>cs /template:Samples"Collections"ArrayList.cst

 

在这个例子中我们使用了ArrayList.cst模版它存储在本地的Samples"Collections文件夹下。下一步我们要去声明我们在最后一步需要创建的XML文件,我们是用/propertyset参数去实现。

 

C:"Program Files"CodeSmith"v3.0>cs /template:Samples"Collections"ArrayList.cst /propertyset:PersonArray.xml

 

这个/property参数用来指定我们的XML属性文件。最后一个我们需要用的参数是/output参数,用来指定输出怎样被保存。

 

C:"Program Files"CodeSmith"v3.0>cs /template:Samples"Collections"ArrayList.cst /propertyset:PersonArray.xml /out:test.cs

 

使用/out参数指定将结果输出到一个叫test.cs文件中保存。执行这个命令后,模板将开始运行,使用属性文件将结果输出到test.cs文件保存。

 

这是大多数情况下有效使用控制台。

 

Merging Output

在各种代码生成中最大的挑战就是将生成的代码和开发人员编写或修改的代码区分开。控制台对这个问题提供了一个有效的独特的解决方案,使用一个指定的参数在当前已存在的代码文件中需要将模板生成的代码添加的地方指定一块区域。

 

下面是一个简单的代码文件,包含了我们要添加生成代码的区域。

using System;

 

namespace Entities

{

      GeneratedOrderEntity

  #region GeneratedOrderEntity

 

      #endregion 

}

我们的目标是将DatabaseSchema"BusinessObject.cst模版生成的代码添加到类文件的GeneratedOrderEntity区域中。和上一个例子一样,使用CodeSmith console控制台应用程序执行这个模版,但是这次要使用另一个参数merge

 

C:"Program Files"CodeSmith"v3.0>cs /template:Samples"DatabaseSchema"BusinessObject.cst /propertyset:OrderEntity.xml /out:OrderEntity.cs /merge:InsertRegion= "RegionName=Sample Generated Region;Language=C#;"

 

使用merge参数我们可以指定区域的名称在这个例子中是GeneratedOrderEntity然后控制台应用程序将执行模版并将结果添加到这个区域中。

 

就像看到的一样,Order类被添加到了我们指定的区域中。在代码文件中使用merge参数生成的内容在其他部分被修改或手写后很容易重新再次生成而不会产生影响。

 

参数介绍Parameter Reference

Specifying Output

/out:<file>指定从模版创建的输出文件的名称。

/out:default指定这个文件被默认保存成模版是用的名称。

/merge:<mergetype>=<init>指定模版输出的区域。可以简写为/m

 

Specifying Input

/template:<file>选择要执行的模版,简写为/t

 

/propertyset:<file>生成代码时需要使用的XML属性文件。简写为/p

 

Compiler Options

/debug[+|-]指定模版需要包含的调试信息。(允许在运行模版时进行调试)

/tempfiles[+|-]指定保留临时文件。(如果在临时文件上调试也可以)

 

Miscellaneous

/help显示帮助信息。

/nologo禁止生成器版权信息。

 

编写CodeSmith自定义属性的编辑器

 

        当你开始编写自定义的CodeSmith模板时,很可能对于使用它的stringsintegers属性很满意,但有时你会发现需要创建一个不同类型的属性,可能是一个自定义的类型或者是.NET framework中但是在属性面板中没有提供的类型。在模板中去作这些很简单,但是怎样指定一个类型在运行模板时显示在属性面板中呢?例如创建了一个Person类并且具有很多不同的属性,但是却没有办法让用户去组装这个类……除非创建一个自定义属性编辑器。

 

        属性面板提供了方法去编写自定义的属性编辑器,当用户在面板上选择一个属性时可以激发相应的方法,同时也可以通过编写代码实现提示用户输入一个必要的值。下面我们举个例子,创建一个接受组建的属性并且是用影射循环贯串所有的类,是所有的类都可以使用它和它的方法,去创建一个NUnit测试基础。(这句翻译的不好,原文:As an example we are going to build a template which accepts an assembly as a property and then using reflection loops through all of the classes, and the methods of those classes, to build NUnit test stubs.

 

        首先,我们来关注一下模板的组件属性,暂且不看自定义编写的代码。模板的第一部分是一些声明定义和属性。将属性放在脚本标签中代替使用属性声明,在下一部分将看到这样做的必要。

 

 1<%@ CodeTemplate Language="C#" TargetLanguage="C#" Description="Builds a class for each class in the assembly, and a test stub for every method." %>

 2

 3<%@ Import NameSpace="System.Reflection" %>

 4

 5<script runat="template">

 6

 7private Assembly assembly;

 8

 9public Assembly AssemblyToLoad

10{

11      get{return assembly;}

12      set{assembly = value;}

13}

14

15</script>

 

        然后我们为组建assembly中的每一个类创建一个类为每一个类创建他的方法。然后直接将模板的输出内容放入Visual Studio.NET,然后在编写组件的单元测试时使用向导。

 

 1using System;

 2using NUnit.Framework;

 3

 4<%

 5      foreach(Type T in AssemblyToLoad.GetTypes())

 6      {

 7            if(T.IsClass)

 8            {

 9                  %>

10

11                  [TestFixture]

12                  public class <%=T.Name%>Tests

13                  {

14                  <%

15                              MethodInfo[] methods = T.GetMethods ( BindingFlags.Public | BindingFlags.Instance | BindingFlags.Static );

16                              foreach(MethodInfo M in methods)

17                              {

18                                    %>

19

20                                    [Test]

21                                    public void <%=M.Name%>Test

22                                    {

23                                          //TODO Write this test

24                                    }                

25                                    <%

26                              }

27

28                  %>}<%

29            }

30      }

31%>

 

        这个模板仅仅可以编译通过,但是由于我们编写显示了一个类型属性面板并不知道如何去操作它,所以我们没有办法自定义指定组件在加载时想要加载的组件。

        我们需要创建一个UITypeEditor,这是一个建立属性面板是用的特殊属性的类。UITypeEditor需要创建在一个和模板分离的组件中,我们是用Visual Studio创建这个类。

 

 /Files/Bear-Study-Hard/AssemblyHelper.zip

        首先我们需要创建一个继承UITypeEditor的类。

1public class AssemblyFilePicker : UITypeEditor

2{

3      public AssemblyFilePicker(): base()

4      {

5      }

6}

        关于UITypeEditor的说明请大家参看MSDNVisual Studio.NET自带帮助中的说明,其中有详细的例子。

        然后我们需要重载UITypeEditor类的两个不同的方法。第一个需要重载点的方法是GetEditStyle,这个方法是告诉属性面板对于当前类型是用什么类型的编辑器,在这个例子中我们设置编辑类型为Modal。这样大家可以在该属性格子的右边看到一个小按钮,它将引发一个对话框等模式的对话(trigger a modal dialog)。这是我们的GetEditStyle方法:

1public override UITypeEditorEditStyle GetEditStyle(ITypeDescriptorContext context)

2{

3      return UITypeEditorEditStyle.Modal;

4}

 

        其中的Modal为显示一个省略号按钮。

 

        需要重载的另一个方法是EditValue方法当用户电击属性时会调用这个方法。按照我们需要加载的组件类型需要创建一个打开文件对话框(open file dialog)然后捕获这个对话框,在属性格子中返回对话框的结果。

 

1public override object EditValue(ITypeDescriptorContext context, IServiceProvider provider, object value)

2{

3

4if (provider != null)

5{

 

        首先我们要从当前的服务和控件中得到一个参考,有了控件的参考我们可以通过它转到ShowDialog方法。原文First we need to get a reference to the current service and control, we need the reference to the control so we can pass it to the ShowDialog method.

 

1IWindowsFormsEditorService editorService = (IWindowsFormsEditorService)provider.GetService(typeof(IWindowsFormsEditorService));

2Control editorControl = editorService as Control;

3

4if (editorControl != null)

5{

        然后我们创建一个openFileDialog类并填入适合的属性。

 

1OpenFileDialog openFileDialog = new OpenFileDialog();                        

2

3openFileDialog.CheckFileExists = true;

4openFileDialog.DefaultExt = ".dll";

5openFileDialog.Multiselect = false;

6openFileDialog.Title = "Select an Assembly:";

7openFileDialog.Filter = "Assembly Files | *.dll";

        然后我们通过控件的参考(reference)将对话框显示给用户。

 

1DialogResult result = openFileDialog.ShowDialog(editorControl);

        下一步我们检查用户是否点击了OK按钮,如果点击了,通过文件选择对话框选择文件后使用LoadForm方法加载这个组件,最后返回这个值。

 

 1if (result == DialogResult.OK)

 2            {

 3Assembly assembly = Assembly.LoadFrom( openFileDialog.FileName ) ;

 4                  value = assembly;

 5            }

 6            else

 7            {

 8                  value = null;

 9            }

10      }

11}

12

13return value;

14}

        这个值将被放在属性面板中并可以被模板读取,但是需要注意,在我们作这个之前要将组件import引入到模板中,并在模板中用一对属性声明。

 

        加载这个模板我们仅需将这个组件assembly与模板放在同一目录下,然后再模板中加入下面两行代码。

 

1<%@ Assembly Name="AssemblyHelper" %>

2<%@ Import NameSpace="AssemblyHelper" %>

原创粉丝点击