CodeSmith 使用教程(17) Merge策略分析

访客 阅读:170 2021-04-01 00:27:10 评论:0


前面介绍了CodeSmith使用的基本用法,通过代码模板来生成代码,但如果你修改了自动生成的代码,再次使用代码模板生成代码后,你修改的代码也就丢失了,CodeSmith 支持多种“合并(Merge)”来解决这个问题,以保留你自己修该过的部分。

CodeSmith支持如下三种“合并策略”:

不过这些策略主要是针对C#,VB这些支持Region的语言,对于其它语言可能就需要使用其它方法,比如自定义Merge策略,CodeSmith允许通过CodeSmith.Engine.IMergeStrategy 来扩展“合并”策略,本人推荐CodeSmith的一个原因就是CodeSmith提供了很多接口而不仅仅是一个工具,比如除了CodeSmith支持的属性,XML属性,你也可以通过 CodeSmith.CustomProperties来自定义属性种类,除了CodeSmith支持的数据源种类(MySQL,Oracle),你也可以通过自定义的Schema Provider 支持新的数据库类型或是其它数据类型。

InsertRegion策略

InsertRegion 顾名思义,就是在源码中定义一个Region,然后让CodeSmith自动生成的代码只插入到该区域,而在区域外的代码CodeSmith不会去碰它们,从而实现了自定义的代码和自动生成代码的合并。

PreserveRegion策略

PreserveRegion 是定义多个区域,然后通知CodeSmith保持这些区域代码不变,自动创建的代码添加到这些区域的外面,和InsertRegion作用相反。

下面还是借用CodeSmith 自带的Merge示例说明一下这两种策略的基本用法:

首先是InsertRegion策略,定义一个类文件InsertRegionSample.cs

  1. public class InsertRegionsSample  
  2. {  
  3.   
  4.     public void SomeCustomMethod()  
  5.     {  
  6.         // This is my custom code that I want to preserve.  
  7.         // I can make changes to it and my changes will  
  8.         // not be overwritten.  
  9.     }  
  10.  
  11.     #region Sample Generated Region  
  12. // This region generated by CodeSmith on Saturday, 12 January 2013  
  13.     #endregion  
  14. }  
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 ,准备让CodeSmith查入代码,编写一个简单的代码模板,插入当前时间:

  1. <%@ Template Language="C#" TargetLanguage="C#"   Description="Demonstrates using an InsertRegion merge strategy in C#." %>  
  2. // This region generated by CodeSmith on <%= DateTime.Now.ToLongDateString() %>  
<%@ Template Language="C#" TargetLanguage="C#"   Description="Demonstrates using an InsertRegion merge strategy in C#." %> 
// This region generated by CodeSmith on <%= DateTime.Now.ToLongDateString() %> 

然后通过CodeSmith项目为模板设置Merge策略:

20130112002

选择InsertRegion策略, 然后设置要插入的RegionName。

生成后的代码如下:

  1. public class InsertRegionsSample  
  2. {  
  3.   
  4.     public void SomeCustomMethod()  
  5.     {  
  6.         // This is my custom code that I want to preserve.  
  7.         // I can make changes to it and my changes will  
  8.         // not be overwritten.  
  9.     }  
  10.  
  11.     #region Sample Generated Region  
  12. // This region generated by CodeSmith on Saturday, 12 January 2013  
  13.     #endregion  
  14. }  
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

  1. public class PreserveRegionsSample  
  2. {  
  3.  
  4. #region "Custom Region 1"  
  5.   
  6.     // This is a place holder for your custom code.  
  7.     // It must exist so that CodeSmith knows where  
  8.     // to put the custom code that will be parsed  
  9.     // from the target source file.  
  10.     // The region name is used to match up the regions  
  11.     // and determine where each region of custom code  
  12.     // should be inserted into the merge result.  
  13.  
  14. #endregion  
  15.   
  16.     public void SomeGeneratedMethod()  
  17.     {  
  18.   
  19.         // This section and all other non-custom code  
  20.         // regions will be overwritten during each  
  21.         // template execution.  
  22.         // Current Date: Saturday, 12 January 2013  
  23.     }  
  24.  
  25. #region "Custom Region 2"  
  26.   
  27.     // The contents of this region will also be preserved  
  28.     // during generation.  
  29.  
  30. #endregion  
  31.   
  32. }  
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 
 
} 

模板定义如下:

  1. <%@ Template Language="C#" TargetLanguage="C#"    Description="Demonstrates using a PreserveRegions merge strategy in C#." %>  
  2. public class PreserveRegionsSample  
  3. {  
  4.  
  5. #region "Custom Region 1"  
  6.   
  7.     // This is a place holder for your custom code.  
  8.     // It must exist so that CodeSmith knows where  
  9.     // to put the custom code that will be parsed  
  10.     // from the target source file.  
  11.     // The region name is used to match up the regions  
  12.     // and determine where each region of custom code  
  13.     // should be inserted into the merge result.  
  14.  
  15. #endregion  
  16.   
  17.     public void SomeGeneratedMethod()  
  18.     {  
  19.   
  20.         // This section and all other non-custom code  
  21.         // regions will be overwritten during each  
  22.         // template execution.  
  23.         // Current Date: <%= DateTime.Now.ToLongDateString() %>  
  24.     }  
  25.  
  26. #region "Custom Region 2"  
  27.   
  28.     // The contents of this region will also be preserved  
  29.     // during generation.  
  30.  
  31. #endregion  
  32.   
  33. }  
<%@ 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 
 
} 

模板中也定义了两个区域,然后为该模板设置Merge策略,使用PreserveRegion时可能有多个Region需要保留,因此可以使用RegX来定义要保留的Region:
20130112003

本例下载

InsertClass 策略用在给以重载的代码中插入自动生成的代码,挺起来和InsertRegion功能很类似,的确也是如此,但InsertClass支持更多的配置,可以实现更加灵活和强大的功能。

它支持的配置有:

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几种选项
NotFoundParent String, no default 如果指定NotFoundAction为InsertInParent对应的父类名称.

比如使用如下配置:

Language: C#
ClassName: “Pet”
PreserveClassAttributes: True
OnlyInsertMatchingClass: True
MergeImports: True

现有类定义:

  1. using System;  
  2. using System.ComponentModel.DataAnnotations;  
  3. namespace Petshop  
  4. {  
  5.     [ScaffoldTable(true)]  
  6.     public class Pet  
  7.     {  
  8.         public int Age { getset; }  
  9.         public string FirstName { getset; }  
  10.         public string LastName { getset; }  
  11.     }  
  12. }  
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; } 
    } 
} 

自动生成的代码如下:

  1. using System;  
  2. using System.Text;  
  3. namespace Petshop  
  4. {  
  5.     public class Pet  
  6.     {  
  7.         public string FirstName { getset; }  
  8.   
  9.         public string LastName { getset; }  
  10.   
  11.         public string FullName  
  12.         {  
  13.             get { return String.Format("{0} {1}", FirstName, LastName); }  
  14.   
  15.         }  
  16.     }  
  17. }  
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 合并后的代码如下:

  1. using System;  
  2. using System.ComponentModel.DataAnnotations;  
  3. using System.Text;  
  4. namespace Petshop  
  5. {  
  6.     [ScaffoldTable(true)]  
  7.     public class Pet  
  8.     {  
  9.         public string FirstName { getset; }  
  10.   
  11.         public string LastName { getset; }  
  12.   
  13.         public string FullName  
  14.         {  
  15.             get { return String.Format("{0} {1}", FirstName, LastName); }  
  16.   
  17.         }  
  18.     }  
  19. }  

声明

1.本站遵循行业规范,任何转载的稿件都会明确标注作者和来源;2.本站的原创文章,请转载时务必注明文章作者和来源,不尊重原创的行为我们将追究责任;3.作者投稿可能会经我们编辑修改或补充。

发表评论
搜索
排行榜
关注我们

一个IT知识分享的公众号