CodeSmith实用技巧(转载)
摘自:TerryLes http://terrylee.cnblogs.com/archive/2005/12/26/304865.html
CodeSmith实用技巧(一):使用StringCollection
StringCollection提供了一种集合的输入方式,在代码中,可以用Array的方式来引用。在使用这个类之前,在模版中我们必须添加对CodeSmith.CustomProperties程序集的引用:
添加完程序集之后,我们就可以使用StringCollection在脚本块中定义一个属性:
%@ Property Name="List" Type="CodeSmith.CustomProperties.StringCollection" Category="Custom" Description="This is a sample StringCollection"%>
执行该模版时,这个属性将在属性窗体中显示为一个按钮:
单击按钮,将会弹出一个String Collection Editor对话框:
当然也可以直接在属性窗口中编辑StringCollection。
模版代码如下:
1
3
<%@ Property Name="List" Type="CodeSmith.CustomProperties.StringCollection" Category="Custom" Description="This is a sample StringCollection" %>
6
7
8
{
11
12
14 /// </summary>
16
18
20
22
24
26
28
31
33
35
生成后的代码:
1
2
6
7
2
public static void Main(string[] args) {
19
21
23
25
27
StringCollection的重要属性和方法:
公共属性
名称 |
描述 |
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实用技巧(二):使用FileNameEditor
FileNameEditor类给我们提供了在CodeSmith属性面板中弹出打开或保存文件对话框的方式,在使用时,首先在模版中得添加对程序集CodeSmith.CustomProperties的引用。然后就可以在模版中定义一个属性来使用FileNameEditor:
1
3
4
8 Category("Custom"), Description("User selected file.")]
10
16
18
20
223
当我们执行该模版时,在属性面板中同样显示为一个按钮:
单击该按钮,弹出一个保存文件的对话框:
我们也可以通过FileDialogAttribute来自定义弹出的对话框,修改模版为:
1
2 [Editor(typeof(FileNameEditor), typeof(System.Drawing.Design.UITypeEditor)),
5
7
2
{
15 get {return _openFileName;}
17 set {_openFileName= value;}
19 }
弹出的对话框如下所示:
当我们想用一个文件夹的名称来代替文件时,可以使用FolderNameEditor类。
1
2
3
5
6
7
8
9
10
11
FileNameEditor重要方法和属性介绍:
公共方法:
名称 |
描述 |
EditValue |
使用由 GetEditStyle 方法提供的编辑器样式编辑指定的对象 |
GetEditStyle |
获取 EditValue 方法所使用的编辑样式 |
CodeSmith实用技巧(三):使用FileDialogAttribute
使用FileDialogAttribute可以设置FileNameEditor中的属性,基本成员如下:
属性 |
描述 |
默认值 |
FileDialogType |
Save or Open |
FileDialogType.Save |
Filter |
Filter string for file extensions |
All Files (*.*)|*.* |
Title |
Dialog box title |
Select propertyname |
DefaultExtension |
Default file extensions |
None |
CheckFileExists |
True to only allow selecting existing files |
False |
CheckPathExists |
True to only allow using existing paths |
False |
在下面这段模版代码中,我们设置了弹出的对话框的类型为打开文件对话框,标题为“Select Input File”。
1
2
3
4
5
6
7
8
9
SchemaExplorer允许我们获取数据库中一些对象的信息。如果你使用的是SQL Server2000数据库,你可以通过扩展属性获取很多对象的有用的信息。例如:SQL Server定义了一个扩展属性来标识表中的唯一标识字段,在模版中可以这样写:
CodeSmith定义的扩展属性包括table columns, view columns, 和 command parameters。
Table columns
view columns
command parameters
另外,每个对象都有一个CS_Description的扩展属性。你也可以通过SQL Server中的系统存储过程sp_addextendedproperty来创建自定义的扩展属性。例如:我们执行如下命令为Customer这张表的ID字段添加一个Caption的扩展属性:
sp_addextendedproperty 'caption', 'Customer ID', 'user', dbo, 'table', Customers, 'column', id
在数据库中执行完这条语句后,CodeSmith中将会在这个字段的扩展属性集合中加上Caption属性。有关SQL Server 中的扩展属性的内容请参考联机丛书。
用CodeSmith生成可变化的代码,其实是先利用CodeSmith生成一个基类,然后自定义其它类继承于该类。当我们重新生成基类时CodeSmith不要接触继承的子类中的代码。看下面的这段模版脚本:
<%= ConstructorParameterName %>)
执行该模版并输入如下数据:
该模版生成的代码可能如下:
1
3
5
6
7
8
9
把生成的文件保存为Account.cs文件。这时我们可以编写第二个类生成Check.cs文件代码:
1
2
3
4
5
6
现在如果需要改变Account Balance的类型为浮点型,我们只需要改变ConstructorParameterType属性为float,并重新生成Account.cs文件即可而不需要直接在Account.cs中进行手工修改,并且不需要修改Check.cs文件的任何代码。
CodeSmith允许我们存储元数据在XML文件中,然后在执行模版时直接打开XML文件填写到属性面板中。
1.XML Property With a Schema
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
这是一个简单的带有Schema的XML Property的例子:
利用这个Schema文件,我们可以定义一个XML Property来在运行时读去元数据。
<%@ CodeTemplate Language="C#" TargetLanguage="Text" Description="Create packing list from XML PO." %>
在运行时,PurchaseOrder属性在属性面板中显示为按钮,单击后弹出一个对话框供用户选择XML文件。
选择一个XML文件。在该例子XML文件内容如下:
1
2
3
4
5
6
7
8
9
10
11
12
13
生成后的代码如下:
2.XML Property Without a Schema
这是一个不带Schema的XML Property的例子。这个模版在运行时可以访问任何XML文件。
概莫版对目标文件的属性并没有定义一个Schema,所以属性在模版中是作为一个XMLDocument。如果我们选择的XML文件如下所示:
1
2
3
4
5
6
7
生成后的代码:
在使用CodeSmith进行代码生成的时候,你可能需要在子模版和父模版之间共享属性。比如,写一个基于数据库生成代码的模版,在每个模版里面都定义了一个名为Server的属性。当你在父模版中使用此属性时,它的值只对父模版起作用。想要设置此值到子模版,可以在父模版中使用CopyPropertiesTo方法,当在父模版中使用此属性时,它的值会发送到子模版中去。下面这段代码展示了如何使用该方法:
在CodeSmith中,要把生成的代码文件输出到文件中,你需要在自己的模版中继承OutputFileCodeTemplate类。
<%@ CodeTemplate Language="C#" TargetLanguage="C#" Inherits="OutputFileCodeTemplate" Description="Build custom access code."%>
OutputFileCodeTemplate主要做两件事情:
1.它添加一个名为OutputFile的属性到你的模版中,该属性要求你必须选择一个文件;
2.模版重载了方法OnPostRender(),在CodeSmith生成代码完成后把相应的内容写入到指定的文件中去。
如果想要自定义OutputFile属性弹出的保存文件对话框,你需要在你的模版中重载OutputFile属性。例如:你希望用户选择一个.cs文件来保存生成的代码,需要在你的模版中添加如下代码:
Filter="C# Files (*.cs)|*.cs", DefaultExtension=".cs")]
CodeSmith实用技巧(九):重载Render方法来控制输出
在CodeSmith中,CodeTemplate.Render方法是在模版执行完成进行模版输出时执行,你可以通过重载CodeTemplate.Render方法来修改CodeSmith输出时的事件处理。例如:你可以修改模版输出时的方式来代替现在默认的方式,下面这段代码展示了在保持CodeSmith默认的窗口显示的同时,把结果输出到两个不同的文件。
<%@ CodeTemplate Language="C#" TargetLanguage="Text" Description="AddTextWriter Demonstration."%>
2
3
4
5
6
7
8
9 this.Response.AddTextWriter(fileWriter1);
10
12 this.Response.AddTextWriter(fileWriter2);
13
16
17
18
19
注意不能忘了base.Render(writer);这句话,否则你将不能获得默认的输出。当重载CodeTemplate.Render方法时,你也可以访问TextWriter,也就是说你也可以直接添加其它的附属信息到模版输出的内容中。
CodeSmith在执行模版时通过调用一些API来完成的,主要经过了以下这几步的操作:
l 编译一个模版
l 显示编译错误信息
l 创建一个新的模版实例
l 用元数据填充模版
l 输出结果
下面这段代码显示了这些操作:
@"Server=(local)\NetSDK;Database=Northwind;Integrated Security=true;");
template.Render(Console.Out);
在这里我们用了Render方法,其实CodeTemplate.RenderToFile和CodeTemplate.RenderToString方法可能更有用,它可以直接让结果输出到文件中或赋给字符型的变量。
如果你需要提供一个复杂的组合用户界面来输入元数据,这时就要添加设计器的支持。换句话说,除此之外没有别的办法来输入你自定义的元数据类型。添加设计器的支持,首先你要创建一个Editor作为自定义的类型,一个Editor其实就一个继承于.NET 中的System.Drawing.Design.UITypeEditor类的子类。
安装CodeSmith后在,在C:\Program File\CodeSmith\ SampleProjects 文件夹下有很多SampleCustomProperties的工程。例如:DropDownEditorProperty是一个把字符串和布尔类型的值结合在一起的元数据,它提供了一个类DropDownEditorPropertyEditor继承于System.Drawing.Design.UITypeEditor。
在使用的时候跟其它的元数据类型是一样,不过别忘记添加对程序集的引用,引用CodeSmith默认的是不认识该类型的。
当用户想要编辑DropDownEditProperty时,单击CodeSmith属性面板将会显示如下的自定义对话框:
在CodeSmith中,如果生成的代码是SQL脚本,则可以在生成代码完成时自动执行生成的代码,也就是在生成的SQL脚本的同时在数据库中创建新的对象。
用BaseTemplates.ScriptUtility对象提供ExecuteScript方法可以实现,如果想在生成代码完成后立即执行生成的脚本,可以很方便的通过重载OnPostRender来实现。
在使用之前,先添加对下列程序集的引用:
看下面的这个例子:
CodeSmith实用技巧(十三):使用CodeTemplateInfo对象
在CodeSmith中使用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 |
Gets the description. |
DirectoryName |
Gets the name of the directory the template is located in. |
FileName |
Gets the name of the template file. |
FullPath |
Gets the full path to the template. |
Language |
Gets the template language. |
TargetLanguage |
Gets the target language. |
看一下一个具体的使用例子:
CodeSmith实用技巧(十四):使用Progress对象
Progress对象可以在CodeSmith生成代码时给用户显示一个进度条,当生成代码的时间很长时非常有用。如果你使用的是CodeSmith Explorer,进度条将显示在Generate按钮的左边:
如果使用的是CodeSmith Studio,进度条将显示在状态栏上:
使用Progress和在WinForm中使用进度条差不多,需要设置它的最大值和步长:
如果想显示出进度,需要调用PerformStep方法:
在CodeSmith中,以下几个快捷键有助于我们快速输入。
1.Ctrl + Shift + C
在空行上,按下Ctrl + Shift + C后将会录入一个代码块。
2.Ctrl + Shift + Q
按下Ctrl + Shift + Q后录入一个脚本块。
3.Ctrl + Shift + V
对代码块反转,如有下面这样一行代码:
在两个大括号之间按下Ctrl + Shift + V后,将变成如下代码:
4.Ctrl + Shift + W
按下Ctrl + Shift + W后会录入一个输出的代码块:
注意:在使用快捷键的时候,如果想要把一段代码之间放在录入的标记中间,首先选中这些代码,再按下快捷键组合。比如我们有一段这样的代码,想把它放在<script>里面。
选中它,再按下Ctrl + Shift + Q后就会变成: