T4语言的语法很简单,可以说一学就会。它不像C#或Java一样有那么多的限制,所以,只要会C#语音,然后再学习一些T4应该注意的地方,那么就OK了。
T4模板的基本结构可以分成5类:指令块(Directive Block)、文本块(Text Block)、代码语句块(Statement Block)、表达式块(Expression Block)和类特性块(Class Feature Block)。
一、指令块(Directive Block)
你只需要记住指令块是以@开头的,比如下面截图中的内容:
和ASP.NET页面的引用一样,它们出现在文件头部,通过<#@…#>表示。其中<#@template…#>指令是必须的,用于定义模板的基本属性,比如:编程语言、基于的文化、是否支持调试等等。比较常用的指令还包括用于引用程序集的<#@assembly…#>、用于导入命名空间的<#@import…#>等等。下面逐一介绍主要内容:
1、<#@import #>
这个主要用于引入命名空间,比如:<#@import namespace=“System.Linq”#>。
2、<#@assembly name="[assembly strong name|assembly file name]"#>
顾名思义这个用于引入dll文件,比如:<#@assembly name=“System.Core.dll”#>。不过这里其实没有必要,因为你只要在当前的引用里添加dll文件就OK了。
3、<#@output extension=""#>
这个用于设置你的输出格式,比如:<#@output extension=".cs"#>,那么你输出的就是.cs文件咯。很好理解,Extension是扩展名的意思嘛。
4、<#@template #>
格式:<#@template language=“C#” hostspecific=“true” debug=“true” inherits=“templateBaseClass” culture=“code” compilerOptions=“options”#>
它主要有两个意思:一个指的是写模板所使用的语言,比如:<#@template language=“C#”#>,表示我这个模板是用C#写的。
另一个很重要的特性是:继承。就是把一些公共的方法抽象到父类中,然后就可以在多个模板中进行复用。这个非常有用,我以后会逐步地介绍。比如:<#@template language=“C#” inherits=“BaseTemplate” debug=“true”#>,BaseTemplate是我写的一个公共父类。
5、<#@include file="" #>
这个很有意思,表示在当前模板中包含另一个文件中的内容。先来一个简单的例子:
- 新建一个空白的文本模板,命名为MyTextTemplate.tt
- 新建一个myText.txt文件,里面写入一些文字:something in myText file
- 在MyTextTemplate.tt模板中输入<#@include file=“myText.txt”#>
- 然后你就可以在MyTextTemplate.tt中看到myText.txt文件中的一些字符
指明文件/程序集的路径:
- $(SolutionDir):当前项目所在解决方案的目录
- $(ProjectDir):当前项目所在的目录
- $(TargetPath):当前项目编译输出文件的绝对路径
- $(TargetDir):当前项目的编译输出目录,即Web项目的bin目录,控制台、类库项目bin目录下的debug或release目录(取决于当前的编译模式)
举个例子:比如我们在E盘根目录新建了一个控制台项目T4Test,解决方案目录为E:\Guo,项目目录为E:\Guo\T4Test,那么此时在Debug编译模式下:
$(SolutionDir)的值为E:\Guo
$(ProjectDir)的值为E:\Guo\T4Test
$(TargetPath)的值为E:\Guo\T4Test\bin\Debug\T4Test.exe
$(TargetDir)的值为E:\Guo\T4Test\bin\Debug
注意事项:
- file的路径可以是相对路径、绝对路径
- file可以包括环境变量,但它必须用%包起来,比如:<#@include file="%HOMEPATH%"\MyIncludeFile.t4#>
- file后面的文件扩展名不能是.tt
如果你的文件需要用.tt结尾,那可以用t4来代替。因为如果你添加了.tt后缀名的文件,VS会自动把当前文件的Custom Tool(自定义工具)属性设定为TextTemplatingFileGenerator。
示例代码一(include在上):
<#@include file="myText.txt"#>
<#var properties = new string[]{"P1","P2","P3"};#>
class GeneratedClass{
<#foreach(string propertyName in properties)
{#>
private int <#= propertyName#>=9;
<#}#>
}
示例一代码截图:
示例二代码(include在下):
<#var properties = new string[]{"P1","P2","P3"};#>
class GeneratedClass{
<#foreach(string propertyName in properties)
{#>
private int <#= propertyName#>=9;
<#}#>
}
<#@include file="myText.txt"#>
示例二代码截图:
6、<#@parameter type=“Full.TypeName” name=“ParameterName” #>
parameter指令声明模板代码中从外部上下文传入的值初始化的属性。如果编写调用文本转换的代码,则可以设置这些值。这些值既可以在Session字典中传递,也可以在CallContext中传递。
可以声明任何远程类型的参数。也就是说,类型必须使用SerializableAttribute进行声明,或者必须从MarshalByRefObject派生。这样可以将参数值传递到在其中处理模板的AppDomain中。可以使用以下内容编写文本模板:
<#@template language="C#"#>
<#@parameter type="System.Int32" name="TimesToRepeat"#>
<#for(int i=0; i<TimesToRepeat; i++;){#>
Line<#=i#>
<#}#>
二、文本块(Text Block)
文本块就是直接原样输出的静态文本,不需要添加任何的标签。从指令块结束到第一个“<#”标签之间的内容就是一段静态的文本块,定义在<#…#>、<#+…#>、<#=…#>之间的都不属于文本块。
模板内容:
<#@template language="C#"#>
Hello World!
编译的内容:
using System;
using Microsoft.VisualStudio.TextTemplating;
namespace Microsoft.VisualStudio.TextTemplating413AE4BE2CE28AB99
{
public class GeneratedTextTransformation: TextTransformation
{
public override string TransformText()
{
this.Write("Hello World!");
return this.GenerationEnvironment.ToString();
}
}
}
输出的是:Hello World!
三、代码语句块(Statement Block)
代码语句块通过<#…#>的形式来表示,中间是一段使用相应的编程语言编写的程序代码,我们可以通过代码语句块控制文本的转化流程。
由于我们使用的是Asp.Net平台,所以在这里代码语句块的作用主要就是写C#代码,示例如下:
<#for (int i = 0; i < 3; i++)
{#>
<#= i #>,
<#}#>
Hello
输出结果如下:
凡是我们平时能在VS里写的代码,都可以在<##>里表示。
四、表达式块(Expression Block)
表达式块通过<#=…#>的形式来表示,它可以动态地解析字符串表达式,并输出到相应的文件中,示例如下:
<#@template language="C#"#>
<#@output extension=".cs" #>
<#var properties = new string[]{"P1","P2","P3"};#>
class GeneratedClass{
<#foreach(string propertyName in properties)
{#>
private int <#= propertyName#>=9;
<#}#>
}
运行结果截图如下:
五、类特性块(Class Feature Block)
类特性块通过<#+…#>的形式来表示,它可以用来定义供调用的方法。
如果文本转化需要一些比较复杂的逻辑,我们需要将其封装成一个单独的方法,甚至是封装成一个单独的类,那就要用到类特性块了,示例如下:
<#@template language="C#"#>
<#HelloWorld();#>
<#HelloWorld();#>
<#+
private void HelloWorld()
{
this.Write("Hello World1");
this.WriteLine("Hello World2");
}
#>
运行结果截图如下:
不过,您需要注意类特性方法必须放到最后面去,如果你这样用:
<#@template language="C#"#>
<#HelloWorld();#>
<#+
private void HelloWorld()
{
this.Write("Hello World1");
this.WriteLine("Hello World2");
}
#>
<#HelloWorld();#>
系统会报错“ErrorGeneratingOutput”,所以大家在使用的时候要特别注意一下:
还有就是类特性块里面并不仅仅是一个方法,它里面还可以放很多东西,比如:属性、字段、常量以及可以在编程语言里看到的其他C#结构,我们可以想象一下它的功能有多么强悍,示例如下:
<#HelloWorld();#>
<#+
private string _field="guoguo";
private void HelloWorld()
{
for (int i = 0; i < 3; i++)
{#>
Hello <#=_field#> World <#=i#>!
<#+}
}
#>
运行结果截图如下:
六、MSDN相关链接
其实对于“T4模板”的学习,讲得最详细的还是MSDN,下面给出对应的链接,有需要的同学可以进行深入的了解。
- T4 文本模板编写准则
- 使用 T4 文本模板生成设计时代码
- 演练:使用文本模板生成代码
- 生成过程中的代码生成
- 文本模板的安全性
- 使用 TextTransform 实用工具生成文件
- 使用 T4 文本模板的运行时文本生成
- 编写 T4 文本模板
- T4 文本模板指令
- T4 模板指令
- T4 参数指令
- T4 输出指令
- T4 程序集指令
- T4 导入指令
- T4 包含指令
- T4 CleanUpBehavior 指令
- 文本模板控制块
- 文本模板实用工具方法
- 从文本模板访问 Visual Studio 或其他主机
- 在文本模板中使用转义序列
- 如何:使用转义序列从模板生成模板
- 调试 T4 文本模板
- 如何:使用文本模板 …
- 自定义 T4 文本转换
- 文本模板转换过程
- 创建自定义 T4 文本模板指令处理器
- 部署自定义指令处理器
- 演练:创建自定义指令处理器
- 在 VS 扩展中调用文本转换
- 使用自定义宿主处理文本模板
- 演练:创建自定义文本模板宿主
- T4 文本模板的 API 参考
- 命名空间
- Microsoft.VisualStudio.TextTemplating
- Microsoft.VisualStudio.TextTemplating.Modeling
- Microsoft.VisualStudio.TextTemplating.VSHost