CodeSmith对象和控制台

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模板时,很可能对于使用它的strings或integers属性很满意,但有时你会发现需要创建一个不同类型的属性,可能是一个自定义的类型或者是.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的说明请大家参看MSDN或Visual 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" %>

本文来自CSDN博客,转载请标明出处:http://blog.csdn.net/zhaili1978/archive/2008/10/28/3167522.aspx

原文地址:https://www.cnblogs.com/luluping/p/1523975.html