编写 T4 文本模板

文本模板包含将从该模板生成的文本。 例如,创建网页的模板将包含“<html>...”HTML 页面的所有其他标准部分。 插入模板是 控制块,它们是程序代码片段。 控制块提供不同的值,并允许文本的某些部分有条件且重复。

此结构使模板易于开发,因为可以从生成的文件的原型开始,并增量插入改变结果的控制块。

文本模板由以下部分组成:

  • 指令 - 控制模板处理方式的元素。

  • 文本块 - 直接复制到输出的内容。

  • 控制块 - 将变量值插入文本的程序代码,并控制文本的条件或重复部分。

若要尝试本主题中的示例,请使用 T4 文本模板将它们复制到模板文件中,如Design-Time 代码生成中所述。 编辑模板文件后,保存该文件,然后检查输出 .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" #>

程序集指令在 预处理的文本模板中不起作用。

有关详细信息,请参阅 T4 程序集指令

命名空间

import 指引与 C# 中的 using 子句或 Visual Basic 中的 imports 子句相同。 它允许引用代码中的类型,而无需使用完全限定的名称:

<#@ import namespace="System.Xml" #>

可以根据需要使用任意数量的 assemblyimport 指令。 必须在文本和控制块之前放置它们。

有关详细信息,请参阅 T4 导入指令

包括代码和文本

include 指令从另一个模板文件插入文本。 例如,此指示插入test.txt的内容。

<#@ include file="c:\test.txt" #>

包含的内容几乎就像如果它本身就是包含文本模板的一部分那样被处理。 但是,即使 include 指令后跟普通文本和标准控制块,你也可以包含一个包含类特性块 <#+...#> 的文件。

有关详细信息,请参阅 T4 Include 指令

实用方法

有多种方法,例如 Write() ,在控制块中始终可用。 它们包括用于帮助缩进输出的方法,以及用于报告错误的方法。

还可以编写自己的实用工具方法集。

有关详细信息,请参阅 文本模板实用工具方法

转换数据和模型

文本模板最有用的应用程序是基于源的内容(如模型、数据库或数据文件)生成材料。 模板提取并重新格式化数据。 模板集合可以将此类源转换为多个文件。

有多种方法可以读取源文件。

读取文本模板中的文件。 这是将数据引入模板的最简单方法:

<#@ import namespace="System.IO" #>
<# string fileContent = File.ReadAllText(@"C:\myData.txt"); ...

将文件加载为可导航模型。 更强大的方法是将数据作为模型读取,文本模板代码可以导航。 例如,可以加载 XML 文件并使用 XPath 表达式进行导航。 还可以使用 xsd.exe 创建一组类,可以使用这些类读取 XML 数据。

在关系图或窗体中编辑模型文件。 Domain-Specific 语言工具提供了用于将模型编辑为关系图或 Windows 窗体的工具。 这样,可以更轻松地与生成的应用程序的用户讨论模型。 Domain-Specific 语言工具还会创建一组反映模型结构的强类型类。 有关详细信息,请参阅 从 Domain-Specific 语言生成代码

设计时模板中的相对文件路径

设计时文本模板中,如果要引用相对于文本模板的位置中的文件,请使用 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 #>

还可以获取主机提供的其他服务。 有关详细信息,请参阅 从模板访问 Visual Studio 或其他主机

设计时文本模板在单独的应用程序域(AppDomain)中运行

应注意, 设计时文本模板 在独立于主应用程序的 AppDomain 中运行。 在大多数情况下,这并不重要,但在某些情况下,你可能会发现限制。 例如,如果要从单独的服务传入或传出模板中的数据,则服务必须提供可序列化的 API。

(对于 运行时文本模板,情况并非如此,因为它会生成与其他代码一起编译的代码。)

编辑模板

可以从扩展管理器联机库下载专用文本模板编辑器。 在 “工具” 菜单上,单击“ 扩展管理器”。 单击 在线图库,然后使用搜索工具。