T4模板

一、为什么叫T4模板
T4(Text Template Transformation Toolkit)是微软官方在Visual Studio 2008中开始使用的代码生成引擎。在Visual Studio中,"T4文本模板"是由一些文本块和控制逻辑组成的混合模板,它可以生成文本文件。在Visual C#或Visual Basic中,控制逻辑编写为程序代码的片段。生成的文件可以是任何类型的文本,例如网页、资源文件或任何语言的程序源代码。现在的VS中只要与代码生成相关的场景基本上都能找T4的身影,比如MVC的视图模板,Entity Framework的DataContext模板等等。

二、模板的两种类型
1、设计时模板
在Visual Studio中执行设计时T4文本模板,以便定义应用程序的部分源代码和其他资源。
通常,您可以使用读取单个输入文件或数据库中的数据的多个模板,并生成一些.cs、.vb或其他源文件。每个模板都生成一个文件。在Visual Studio或MSBuild内执行它们。
若要创建设计时模板,请向您的项目中添加“文本模板”文件。另外,您还可以添加纯文本文件并将其“自定义工具”属性设置为“TextTemplatingFileGenerator”。
2、运行时模板
可在应用程序中执行运行时T4文本模板(“预处理过的”模板)以便生成文本字符串(通常作为其输出的一部分)。
若要创建运行时模板,请向您的项目中添加“已预处理的文本模板”文件。另外,您还可以添加纯文本文件并将其“自定义工具”属性设置为“TextTemplatingFilePreprocessor”

三、文本模板的组成

3.1  指令

1.T4模板指令 

<#@ template {language="C#"} {debug="false"} {hostspecific="false"}  {compilerOptions="options"} {culture="code"} {inherits="Microsoft.VisualStudio.TextTemplating.VSHost.ModelingTextTransformation"} #>
1.模板指令中所有特性均为可选的。
2.language:输出语言,有效值C#、VB,默认为C#。
3.debug:是否启用测试,有效值true、false,默认值为false。特别说明下这个调试真的不咋地,很容易让VS崩溃,很鸡肋的功能。
4.hostspecific:有效值true、false,默认为false。如果将此特性的值设置为true,则会将名为Host的属性添加到由文本模板生成的类中。该属性是对转换引擎的宿主的引用,并声明为:Microsoft.VisualStudio.TextTemplating.ITextTemplatingEngineHost。
5.inherits:可以指定模板的程序代码可以继承自另一个类,这个类也可以从文本模板生成。目前没有使用过,基本上可以忽略。
6.compilerOptions:有效值为任何有效的编译器选项。基本上可以忽略

2.T4参数指令
<#@ parameter type="Full.TypeName" name="ParameterName" #>
顾名思义,就是用来传参的,应该是用在运行时模板的(预处理模板)。

3.T4输出指令
<#@ output extension=".txt" {encoding="utf-8"} #>
比较重要的指令,用于设置输出文件的后缀名和文件编码
extension:输出文件扩展名,默认为“.cs”
encoding:文件编码,默认为utf-8(这里不能确定,我测试是utf-8)。

4、T4 程序集指令
<#@ assembly name="[assembly strong name|assembly file name]" #>
1.程序集指令相当于VS里面我们添加程序集引用的功能,该指令只有一个参数name,用以指定程序集名称,如果程序集已经在GAC里面注册,那么只需要写上程序集名称即可,如<#@ assembly name="System.Data.dll" #>,否则需要指定程序集的物理路径。
2.T4模板的程序集引用是完全独立的,也就是说我们在项目中引用了一些程序集,然后项目中添加了一个T4模板,T4模板所需要的所有程序集引用必须明确的在模板中使用程序集执行引用才可以。
3.T4模板自动加载以下程序集Microsoft.VisualStudio.TextTemplating.1*.dll、System.dll、WindowBase.dll,如果用到了其它的程序集需要显示的使用程序集添加引用才可以。
4.可以使用$(variableName)语法引用Visual Studio或MSBuild变量(如$(SolutionDir)),以及使用%VariableName%来引用环境变量。介绍几个常用的$(variableName)变量:
$(SolutionDir):当前项目所在解决方案目录
$(ProjectDir):当前项目所在目录
$(TargetPath):当前项目编译输出文件绝对路径
$(TargetDir):当前项目编译输出目录,即web项目的Bin目录,控制台、类库项目bin目录下的debug或release(取决于当前的编译模式)
举个例子:比如我们在D盘根目录建立了一个控制台项目TestConsole,解决方案目录D:LzrabbitRabbit,项目目录为D:LzrabbitRabbitTestConsole,那么此时在Debug编译模式下
$(SolutionDir)的值为D:LzrabbitRabbit。
$(ProjectDir)的值为D:LzrabbitRabbitTestConsole。
$(TargetPath)的值为D:LzrabbitRabbitTestConsoleinDebugTestConsole.exe。
$(TargetDir)的值为D:LzrabbitRabbitTestConsoleinDebug。

5、T4导入指令
<#@ import namespace="System.Linq" #>
在Visual Studio T4文本模板的代码块中,import指令允许您在不提供完全限定名称的情况下引用另一个命名空间中的元素。它等效于C#的using或visual Basic中的imports。默认已经导入了System命名空间的引用。

6、T4包含指令
<#@ include file="filePath" #>
1.filePath可以是绝对的或相对于当前的模板文件。
2.filePath可以包含用"%"分割的环境变量,例如:<#@ include file="%HOMEPATH%MyIncludeFile.t4" #>
3.所包含的文件的名称不必使用扩展名".tt"。可能需要针对包含的文件使用其他扩展名,例如:".t4"。这是因为,在您将.tt文件添加到项目中时,Visual Studio会自动将其“自定义工具”属性设置为TextTemplatingFileGenerator。您通常不希望单独转换包含的文件。
4.在处理时,被包含内容就像是包含文本模板的组成部分一样。不过,即使include指令后为普通文本块和标准控制块,也可以包括含有类功能块<#+...#>的文件。
5.包含指令可以提高代码复用率,比如我们可以将一些常用的程序集、命名空间引用放到一个文件里,使用时仅需要引用下即可,省去了每次都要重新引用一遍的烦恼,如我们建立Reference.ttinclude文件,里面包含了我们平时常用的程序集。
<#@ template debug="false" hostspecific="false" language="C#" #>
<#@ assembly name="System.Core" #>
<#@ import namespace="System.Linq" #>
<#@ import namespace="System.Text" #>
<#@ import namespace="System.Collections.Generic" #>
<#@ output extension=".txt" #>
使用时只需要使用包含指令引用下即可
<#@ include file="$(ProjectDir)Reference.ttinclude" #>。

3.2  文本块
文本块直接向输出文件插入文本。文本块没有特殊格式。例如:下面的文本模板将生成一个单词“Hello World”
<#@ output extension=".txt" #>
Hello World!

3.3 控制块
控制块是用于转换模板的程序代码节。默认语言是C#,但若要使用Visual Basic,可以在文件开头编写以下指令:
<#@ template language="VB" #>
用于编写控制块代码的语言与生成的文本的语言无关。
1.标准控制块
标准控制块是生成输出文件部件的程序代码节。
在模板文件中,可以混合使用任意数量的文本块和标准控制块。但是,不能再控制块中嵌套控制块。每个标准控制块都以<#...#>符合分割。
例如,如果使用下面的控制块和文本,则输出文件包含行“0,1,2,3,4 Hello!”:
<#
   for(int i=0;i<4;i++)
   {
      Write(i+",");
   }
    Write("4");
 #>Hello !
您可以交错文本和代码,而不必使用显示Write()语句。以下示例输出"Hello!"四次:
<#
   for(int i=0;i<4;i++)
   {
#>
Hello!
<# 
  }
#>

2.表达式控制块
表达式控制块计算表达式并将其转换为字符串。该字符串将插入到输出文件中。
表达式控制块以<#=...#>符合分割。
例如,如果使用下面的控制块,则输出文件包含“5”:
<#= 2+3 #>
请注意:开始符号有三个字符"<#="。
表达式可以包含作用域中的任何变量。例如:下面的块输出数字行:
<#
   for(int i=0;i<4;i++)
   {
 #>
 This is hello number <#= i+1 #>:Hello!
 <#
   }
  #>
输出:
 This is hello number 1:Hello!
  This is hello number 2:Hello!
  This is hello number 3:Hello!
  This is hello number 4:Hello!

3.类功能控制块
类功能控制块定义属性、方法或不应包含在主转换中的所有其他代码。类功能块常用于编写帮助器函数。通常,类功能块位于单独的文件中,这样它们可以包含在多个文本模板中。
类功能控制块以<#+...#>符号分割,可以简单的认为<#+...#>定义的内容为我们的类文件。

示例程序

1、新建一个winform应用程序。
2、右键->添加->新建项目:选择文本模板,更改名称:PocoModel.tt。

原文地址:https://www.cnblogs.com/dotnet261010/p/7363200.html