前面介紹了 CodeSmith 使用的基本用法,通過代碼模板來生成代碼,但如果你修改了自動生成的代碼,再次使用代碼模板生成代碼后,你修改的代碼也就丟失了,CodeSmith 支持多種“合并(Merge)”來解決這個問題,以保留你自己修該過的部分。
CodeSmith 支持如下三種“合并策略”:
不過這些策略主要是針對 C#,VB 這些支持 Region 的語言,對于其它語言可能就需要使用其它方法,比如自定義 Merge 策略,CodeSmith 允許通過 CodeSmith.Engine.IMergeStrategy 來擴(kuò)展“合并”策略,本人推薦 CodeSmith 的一個原因就是 CodeSmith 提供了很多接口而不僅僅是一個工具,比如除了 CodeSmith 支持的屬性,XML 屬性,你也可以通過 CodeSmith.CustomProperties 來自定義屬性種類,除了 CodeSmith 支持的數(shù)據(jù)源種類(MySQL,Oracle),你也可以通過自定義的 Schema Provider 支持新的數(shù)據(jù)庫類型或是其它數(shù)據(jù)類型。
InsertRegion 顧名思義,就是在源碼中定義一個 Region,然后讓 CodeSmith 自動生成的代碼只插入到該區(qū)域,而在區(qū)域外的代碼 CodeSmith 不會去碰它們,從而實(shí)現(xiàn)了自定義的代碼和自動生成代碼的合并。
PreserveRegion 是定義多個區(qū)域,然后通知 CodeSmith 保持這些區(qū)域代碼不變,自動創(chuàng)建的代碼添加到這些區(qū)域的外面,和 InsertRegion 作用相反。
下面還是借用 CodeSmith 自帶的 Merge 示例說明一下這兩種策略的基本用法:
首先是 InsertRegion 策略,定義一個類文件 InsertRegionSample.cs
public class InsertRegionsSample
{
public void SomeCustomMethod()
{
// This is my custom code that I want to preserve.
// I can make changes to it and my changes will
// not be overwritten.
}
#region Sample Generated Region
// This region generated by CodeSmith on Saturday, 12 January 2013
#endregion
}
其中定義了一個 Region,名為 Sample Generated Region ,準(zhǔn)備讓 CodeSmith 查入代碼,編寫一個簡單的代碼模板,插入當(dāng)前時間:
<%@ Template Language="C#" TargetLanguage="C#" Description="Demonstrates using an InsertRegion merge strategy in C#." %>
// This region generated by CodeSmith on <%= DateTime.Now.ToLongDateString() %>
然后通過 CodeSmith 項(xiàng)目為模板設(shè)置 Merge 策略:
選擇 InsertRegion 策略, 然后設(shè)置要插入的 RegionName。
生成后的代碼如下:
public class InsertRegionsSample
{
public void SomeCustomMethod()
{
// This is my custom code that I want to preserve.
// I can make changes to it and my changes will
// not be overwritten.
}
#region Sample Generated Region
// This region generated by CodeSmith on Saturday, 12 January 2013
#endregion
}
可以看到 CodeSmith 只在 Region 處插入代碼,而該 Region 外的部分保持不變。
類似的 PreserveRegions 策略,代碼和模板定義如下: PreserveRegionsSample.cs
public class PreserveRegionsSample
{
#region "Custom Region 1"
// This is a place holder for your custom code.
// It must exist so that CodeSmith knows where
// to put the custom code that will be parsed
// from the target source file.
// The region name is used to match up the regions
// and determine where each region of custom code
// should be inserted into the merge result.
#endregion
public void SomeGeneratedMethod()
{
// This section and all other non-custom code
// regions will be overwritten during each
// template execution.
// Current Date: Saturday, 12 January 2013
}
#region "Custom Region 2"
// The contents of this region will also be preserved
// during generation.
#endregion
}
模板定義如下:
<%@ Template Language="C#" TargetLanguage="C#" Description="Demonstrates using a PreserveRegions merge strategy in C#." %>
public class PreserveRegionsSample
{
#region "Custom Region 1"
// This is a place holder for your custom code.
// It must exist so that CodeSmith knows where
// to put the custom code that will be parsed
// from the target source file.
// The region name is used to match up the regions
// and determine where each region of custom code
// should be inserted into the merge result.
#endregion
public void SomeGeneratedMethod()
{
// This section and all other non-custom code
// regions will be overwritten during each
// template execution.
// Current Date: <%= DateTime.Now.ToLongDateString() %>
}
#region "Custom Region 2"
// The contents of this region will also be preserved
// during generation.
#endregion
}
模板中也定義了兩個區(qū)域,然后為該模板設(shè)置 Merge 策略,使用 PreserveRegion 時可能有多個Region 需要保留,因此可以使用 RegX 來定義要保留的 Region:
本例下載
InsertClass 策略用在給以重載的代碼中插入自動生成的代碼,挺起來和 InsertRegion 功能很類似,的確也是如此,但 InsertClass 支持更多的配置,可以實(shí)現(xiàn)更加靈活和強(qiáng)大的功能。
它支持的配置有:
Language | String, Required | 只支持VB和C# |
---|---|---|
ClassName | String, Required | 需插入代碼的類名. |
PreserveClassAttributes | Boolean, defaults to False | 是否保留類已有的Attributes,缺省CodeSmith替代類原來的Attributes |
OnlyInsertMatchingClass | Boolean, defaults to False | 是否只插入匹配的類定義中 |
MergeImports | Boolean, defaults to False | 是否合并Import語句 |
NotFoundAction | Enum, defaults to None | 如果指定的類沒找到后的行動,可以None,InsertAtBottom,InsertInParent幾種選項(xiàng) |
NotFoundParent | String, no default | 如果指定NotFoundAction為InsertInParent對應(yīng)的父類名稱. |
比如使用如下配置:
Language: C# ClassName: “Pet” PreserveClassAttributes: True OnlyInsertMatchingClass: True MergeImports: True
現(xiàn)有類定義:
using System;
using System.ComponentModel.DataAnnotations;
namespace Petshop
{
[ScaffoldTable(true)]
public class Pet
{
public int Age { get; set; }
public string FirstName { get; set; }
public string LastName { get; set; }
}
}
自動生成的代碼如下:
using System;
using System.Text;
namespace Petshop
{
public class Pet
{
public string FirstName { get; set; }
public string LastName { get; set; }
public string FullName
{
get { return String.Format("{0} {1}", FirstName, LastName); }
}
}
}
使用 InsertClass 合并后的代碼如下:
using System;
using System.ComponentModel.DataAnnotations;
using System.Text;
namespace Petshop
{
[ScaffoldTable(true)]
public class Pet
{
public string FirstName { get; set; }
public string LastName { get; set; }
public string FullName
{
get { return String.Format("{0} {1}", FirstName, LastName); }
}
}
}
更多建議: