T4即为Text Template Transformation Toolkit,一种可以由自己去自定义规则的代码生成器。根据业务模型可生成任何形式的文本文件或供程序调用的字符串
在VS中T4模板是没有智能提示和颜色标注的,可以安装官方推荐插件:tangibleT4EditorPlusModellingTools
9.1 T4 文本模板有两种类型
- 设计时模版
可在应用程序中执行运行时 T4 文本模板("预处理过的"模板)以便生成文本字符串(通常作为其输出的一部分)。
若要创建运行时模板,请向您的项目中添加"已预处理的文本模板"文件。 另外,您还可以添加纯文本文件并将其"自定义工具"属性设置为"TextTemplatingFilePreprocessor"。
- 运行时模版
在 Visual Studio 中执行设计时 T4 文本模板,以便定义应用程序的部分源代码和其他资源。
通常,您可以使用读取单个输入文件或数据库中的数据的多个模板,并生成一些 .cs、.vb 或其他源文件。 每个模板都生成一个文件。
若要创建设计时模板,请向您的项目中添加"文本模板"文件。 另外,您还可以添加纯文本文件并将其"自定义工具"属性设置为"TextTemplatingFileGenerator"。
9.2 文本模板的组成
9.2.1 指令
- 模版指令
<#@ template debug="false" hostspecific="false" language="C#" #> |
模板指令中所有特性均为可选的。其中需要说明的是 hostspecific ,如果将此特性设为true,则会将名为Host的属性添加到由文本模板生成的类中。该属性是对象转换引擎的宿主的引用,并声明为Microsoft.VisualStudio.TextTemplating.ITextTemplatingEngineHost 类型。
- 参数指令
顾名思义,就是用来传参的,出现在运行时模板中。
- 输出指令
<#@ output extension=".fileNameExtension" [encoding="encoding"] #> |
- 程序集指令
<#@ assembly name="System.Core" #> |
程序集指令相当于VS里面我们添加程序集引用的功能。T4模版的程序集引用是完全独立的。
可以使用 $(variableName) 语法引用 Visual Studio的变量。几个常用的变量如下:
- $(SolutionDir):当前项目所在解决方案目录
- $(ProjectDir):当前项目所在目录
- $(TargetPath):当前项目编译输出文件绝对路径
- $(TargetDir):当前项目编译输出目录,即web项目的Bin目录
- 导入指令
<#@ import namespace="namespace" #> |
import 指令允许您在不提供完全限定名称的情况下引用另一个命名空间中的元素。 它等效于 C# 中的 using。
- 包含指令
<#@ include file="filePath" #> |
包含指令可以提高代码复用率,比如我们可以将一些常用的程序集、命名空间引用放到一个文件里,使用时仅需要引用下即可,省去了每次都要重新引用一遍的烦恼
<#@ output extension=".txt" #> |
9.2.2 控制块
控制块是用于转换模板的程序代码节
<# for(int i = 0; i < 4; i++) { Write(i + ","); } Write("4"); #> Hello! |
也可以交错文本和代码,而不必使用显式 Write() 语句。 以下示例输出"Hello!"四次:
<# for(int i = 0; i < 4; i++) { #> Hello! <# } #> |
在代码中,可以使用 Write()语句的位置都可以插入文本块。
<#= 2 + 3 #> |
-
类功能控制块
类功能控制块定义属性、方法或不应包含在主转换中的所有其他代码。 类功能块常用于编写帮助器函数。 通常,类功能块位于单独的文件中,这样它们可以包含在多个文本模板中。
<#@ output extension=".txt" #> Squares: <# for(int i = 0; i < 4; i++) { #> The square of <#= i #> is <#= Square(i+1) #>. <# } #> That is the end of the list. <#+ // 定义方法 private int Square(int i) { return i*i; } #> |
9.3 案例:创建模型
可以借助 DbHelper.ttinclude 和 Manager.ttinclude 两个第三方资源提高T4模板的开发效率。
DbHelper.ttinclude 的主要方法:
DbHelper.GetDbTables() :获取指定数据库的所有表。
DbHelper.GetDbColumns():获取指定表的所有列。
Manager.ttinclude 的主要方法:
另外,数据库的连接字符串在Config类(DbHelper.ttinclude 文件)中。
<#@ template debug="false" hostspecific="true" language="C#" #> <#@ assembly name="System.Core" #> <#@ assembly name="System.Data.dll" #> <#@ assembly name="System.Data.DataSetExtensions.dll" #> <#@ import namespace="System.Data" #> <#@ import namespace="System.Data.sqlClient" #> <#@ import namespace="System.Linq" #> <#@ import namespace="System.Text" #> <#@ import namespace="System.Collections.Generic" #> <#@ output extension=".cs" #> <#@ include file="../Common/CodeTemplates/DbHelper.ttinclude"#> <#@ include file="../Common/CodeTemplates/Manager.ttinclude"#>
<# var manager = Manager.Create(Host,GenerationEnvironment); var tables=DbHelper.GetDbTables(Config.ConnectionString,Config.DbDatabase); foreach (DbTable table in tables) { manager.StartNewFile(table.TableName+".cs"); #> using System; namespace Model { public class <#=table.TableName#> { <# foreach(var col in DbHelper.GetDbColumns(Config.ConnectionString,Config.DbDatabase,table.TableName)) { #> public <#=col.CSharpType#><# if(col.CommonType.IsValueType && col.IsNullable){#>?<#}#> <#=col.ColumnName#> { get; set; }
<# } #> } } <# } manager.Process(true); #> |