编写 T4 文本模板
文本模板包含将从其生成的文本。 例如,用于创建网页的模板包含“<html>…”和 HTML 页的所有其他标准部件。
使用这一结构很容易开发模板,因为可以以生成文件为原型,然后逐步插入用于改变结果的控制块。
文本模板由以下部件组成:
指令 - 控制模板处理方式的元素。
文本块 - 直接复制到输出的内容。
控制块 - 向文本插入可变值并控制文本的条件或重复部件的程序代码。
若要尝试本主题中的示例,请将它们复制到模板文件中,如使用 T4 文本模板生成设计时代码所述。 编辑模板文件后,保存该文件,然后检查输出 .txt文件。
文本模板指令向文本模板化引擎提供关于如何生成转换代码和输出文件的一般指令。
例如,下面的指令指定输出文件应具有 .txt 扩展名:
<#@ output extension=".txt" #>
有关指令的详细信息,请参阅T4 文本模板指令。
文本块直接向输出文件插入文本。 文本块没有特殊格式。 例如,下面的文本模板将生成一个包含单词“Hello”的文本文件:
<#@ output extension=".txt" #> Hello
控制块是用于转换模板的程序代码节。 默认语言是 C#,但若要使用 Visual Basic,可以在文件开头编写以下指令:
<#@ template language="VB" #>
用于编写控制块代码的语言与生成的文本的语言无关。
标准控制块是生成输出文件部件的程序代码节。
在模板文件中,可以混合使用任意数量的文本块和标准控制块。 但是,不能在控制块中嵌套控制块。 每个标准控制块都以 <# ... #> 符号分隔。
例如,如果使用下面的控制块和文本块,则输出文件包含行“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! <# } #>
在代码中,可以使用 Write(); 语句的位置都可以插入文本块。
![]() |
---|
在复合语句(例如循环或条件语句)中嵌入文本块时,请始终使用大括号 {...} 来包含文本块。 |
表达式控制块计算表达式并将其转换为字符串。 该字符串将插入到输出文件中。
表达式控制块以 <#= ... #> 符号分隔。
例如,如果使用下面的控制块,则输出文件包含“5”:
<#= 2 + 3 #>
请注意,开始符号有三个字符“<#=”。
表达式可以包含作用域中的任何变量。 例如,下面的块输出数字行:
<#@ output extension=".txt" #> <# for(int i = 0; i < 4; i++) { #> This is hello number <#= i+1 #>: Hello! <# } #>
类功能控制块定义属性、方法或不应包含在主转换中的所有其他代码。 类功能块常用于编写帮助器函数。 通常,类功能块位于单独的文件中,这样它们可以包含在多个文本模板中。
类功能控制块以 <#+ ... #> 符号分隔。
例如,下面的模板文件声明并使用一个方法:
<#@ 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. <#+ // Start of class feature block private int Square(int i) { return i*i; } #>
类功能必须编写在文件末尾。 不过,即使 include 指令后跟标准块和文本,也可以 <#@include#> 包含类功能的文件。
有关控制块的详细信息,请参阅文本模板控制块。
可以编写生成文本的方法。 例如:
List of Squares: <# for(int i = 0; i < 4; i++) { WriteSquareLine(i); } #> End of list. <#+ // Class feature block private void WriteSquareLine(int i) { #> The square of <#= i #> is <#= i*i #>. <#+ } #>
将文本生成方法放置在可供多个模板包含的单独文件中,是非常有用的。
模板的代码块可以使用定义了最常用 .NET 程序集(如 System.dll)的类型。 此外,也可以引用其他 .NET 程序集或你自己的程序集。 你可以提供程序集的路径或强名称:
<#@ assembly name="System.Xml" #>
应该使用绝对路径名,或在路径名中使用标准宏名。 例如:
<#@ assembly name="$(SolutionDir)library\MyAssembly.dll" #>
有关宏的列表,请参阅用于生成命令和属性的宏。
在预处理文本模板中,assembly 指令无效。
有关详细信息,请参阅T4 程序集指令。
import 指令与 C# 中的 using 子句或 Visual Basic 中的 imports 子句相同。 通过该指令,不使用完全限定名就可以在代码中引用类型:
<#@ import namespace="System.Xml" #>
可以根据需要使用任意多个 assembly 和 import 指令。 必须将它们放在文本块和控制块之前。
有关详细信息,请参阅T4 导入指令。
include 指令插入其他模板文件的文本。 例如,下面的指令插入 test.txt 的内容。
<#@ include file="c:\test.txt" #>
在处理时,被包含内容就像是包含文本模板的组成部分一样。 不过,即使 include 指令后跟普通文本块和标准控制块,也可以包含编写有类功能块<#+...#> 的文件。
有关详细信息,请参阅T4 包含指令。
对于文本模板而言,最有用的应用是根据源(如模型、数据库或数据文件)的内容生成材料。 模板提取数据并重新设置数据格式。 模板集合可以将此类源转换为多个文件。
有几种方法可以读取源文件。
在文本模板中读取文件。 下面是将数据读入模板的最简单的方法:
<#@ import namespace="System.IO" #> <# string fileContent = File.ReadAllText(@"C:\myData.txt"); ...
将文件作为可导航模型加载。 更有效的方法是将数据作为模型读取,文本模板代码可以导航该模型。 例如,可以加载 XML 文件,然后使用 XPath 表达式对其导航。 还可以使用 xsd.exe 创建一组类,使用这些类可读取 XML 数据。
在关系图或窗体中编辑模型文件。使用 特定于域的语言工具 提供的工具可以将模型作为关系图或 Windows 窗体进行编辑。 这样便于与生成的应用程序的用户讨论模型。 特定于域的语言工具 还创建一组反映模型结构的强类型类。 有关详细信息,请参阅从域特定语言生成代码。
使用 UML 模型。 可以从 UML 模型生成代码。 这种方式的优点在于,可以以熟悉的表示法将模型作为关系图进行编辑。 此外,无需设计关系图。有关详细信息,请参阅从 UML 模型生成文件。
在设计时文本模板中,若要引用相对于文本模板的位置中的文件,请使用 this.Host.ResolvePath()。 还必须在 template 指令中设置hostspecific="true":
<#@ template hostspecific="true" language="C#" #> <#@ output extension=".txt" #> <#@ import namespace="System.IO" #> <# // Find a path within the same project as the text template: string myFile = File.ReadAllText(this.Host.ResolvePath("MyFile.txt")); #> Content of MyFile.txt is: <#= myFile #>