你必须懂的 T4 模板:深入浅出

示例代码:示例代码__你必须懂的T4模板:浅入深出.rar

 

(一)什么是T4模板?

T4,即4个T开头的英文字母组合:Text Template Transformation Toolkit。

T4文本模板,即一种自定义规则的代码生成器。根据业务模型可生成任何形式的文本文件或供程序调用的字符串。(模型以适合于应用程序域的形式包含信息,并且可以在应用程序的生存期更改)

 

VS本身只提供一套基于T4引擎的代码生成的执行环境,由下面程序集构成:

Microsoft.VisualStudio.TextTemplating.10.0.dll

Microsoft.VisualStudio.TextTemplating.Interfaces.10.0.dll

Microsoft.VisualStudio.TextTemplating.Modeling.10.0.dll

Microsoft.VisualStudio.TextTemplating.VSHost.10.0.dll

 

便利工具:

1、  T4Toolbox.msi(CodePlex上开源的工具)

a)         提供一些可以直接使用的代码生成器,比如Enum SQL View、AzMan wrapper、LINQ to SQL classes、LINQ to SQL schema和Entity Framework DAL等。

b)         提供一些基于T4方面的VS的扩展:当你安装之后,在“Add New Item”对话框中就会多出一个命名为“Code Generation”的类别,其中包括若干文件模板。

2、  T4 模板编辑器(eg:支持代码着色、智能提示)

a)         tangible T4 Editor (下载)

b)         Visual T4 (下载)

    当然我们也可以通过VS2010中新增的扩展管理器(Extension Manager)来添加Vs扩展插件。扩展管理器(Extension Manager),这和Eclipse/Netbeans有些相似,用户可以直接在IDE中从Visual Studio 库(Visual Studio Gallery)找到并下载扩展。通过VS的菜单Tools->Extension Manager,这里你可以添加,删除已经安装的VS的扩展插件。打开界面如下:

 

 

笔者在学习 T4 的时候使用过上面两个 T4 模板编辑器。稍作几点对比:

a)         tangible T4 Editor可选择安装内嵌的 UML 模板模型

       

b)         对于不是常用的dll( eg:EnvDTE.dll ),tangible T4 Editor免费版和 Visual T4 都不支持导航,并且所报的提示页不一样

tangible T4 Editor免费版中提示如下:

 

 

Visual T4中则直接提示:

 

但是在 Visual T4 中,我们可以通过在程序集中引入 EnvDTE.dll 解决此错误的提示(完成开发后可移除程序集引用),并且还能完美的获得该程序集的智能提示功能,如下图所示:

 

         同时我们也可以看到 Visual T4 中代码着色也更加贴近 VS (蓝色字体标注对象)。

小结:

  1. 就“代码着色”和“智能提示”方面Visual T4 工具表现更完美(前提是必须主动在项目中引入对应程序集),但目前最新版本存在缩进问题实在可惜,悲愤中等更新。.
  2. 可能你还想要tangible T4 Editor提供的 UML 模板模型,呵呵……现在我本机同时装了这两款 T4编辑器,暂时还没发现冲突。

 

(二)T4基本结构

T4模板可以分为:指令块、文本块、控制块。

  1. 指令块 - 向文本模板化引擎提供关于如何生成转换代码和输出文件的一般指令。
  2. 文本块 - 直接复制到输出的内容。
  3. 控制块 - 向文本插入可变值并控制文本的条件或重复部件的程序代码,不能在控制块中嵌套控制块。

n  指令块

6个指令<#@ template #>、<#@ parameter#>、<#@ assembly #>、<#@ import #>、<#@ include #>、<#@ output #>、

其中, output 和 assembly 只能用在设计时模板。

1)         T4 模板指令

<#@ template [language="C#"] [hostspecific="true"] [debug="true"] [culture="code"] [inherits="templateBaseClass"] [compilerOptions="options"] #>

这里只说明下 inherits 属性,其余属性在本文更合适的地方有进行说明。

inherits             

指定模板的程序代码继承自另一个类,该基类可以是由其他模板生成。

1)         运行时(预处理过的)文本模板中的继承

如果不指定 inherits 特性,则会从您的文本模板生成基类和派生类。指定 inherits 特性时,仅生成派生类。

2)         设计时文本模板中的继承

设计时模板会生成任何类型的“文本文件”,此文件将组成 Visual Studio 项目的一部分。T4 模板引擎首先要将模板转换为中间程序代码文件,中间代码文件将写入您的 %TEMP% (环境变量)目录。默认该生成的中间代码继承自 Microsoft.VisualStudio.TextTemplating.TextTransformation 类,但你也可根据需求使用 inherits 特性指定派生于 TextTransformation 类的任何基类。

                   模板引擎生成转换类更详细的请参考本文后面的 何时编译,编译过程  节。

 

2)         T4 参数指令

<#@ parameter type="Full.TypeName" name="ParameterName" #>

在 Visual Studio 文本模板中,parameter 指令声明模板代码中从自外部上下文传入的值初始化的属性。可以声明任何远程类型的参数。也就是说,类型必须使用SerializableAttribute进行声明,或者必须从MarshalByRefObject派生。这样可以将参数值传递到在其中处理模板的AppDomain中。

如何使用及内部运作机制请查看我的另一篇文章 《(译)理解 T4 模板:<#@ parameter #> 指令》 。

 

3)         T4 导入指令

<#@ import namespace="namespace" #>

 

4)         T4 包含指令

<#@ include file="filePath" #>

a)         为了增加代码的可维护性,将公用函数做为类功能块(<#+ 类功能控制块 #>)存放在单独的文件中,该文件可以被 <#@include#> 到一个或多个模板文件中。

b)         对于包含文件,文件扩展名使用 .ttinclude可读性更好。(以区分后缀为 .tt的运行时或设计时文本模板)

 

5)         T4 输出指令

<#@ output extension=".fileNameExtension" [encoding="encoding"] #>

运行时(预处理)文本模板中不需要 output 指令。应用程序通过调用TextTransform() 来获取已生成的字符串。

 

6)         T4 程序集指令

<#@ assembly name="[assembly strong name|assembly file name]" #>

在预处理文本模板中,assembly 指令无效。改为在 Visual Studio 项目中直接“添加引用”。

程序集名称应为以下各项之一:

  1. GAC 中程序集的强名称,例如 System.Xml.dll。还可以使用长名称,例如 name="System.Xml, Version=4.0.0.0, Culture=neutral,PublicKeyToken=b77……"。
  2. 程序集的绝对路径

可以使用 $(variableName) 语法引用 Visual Studio 或MSBuild变量(如 $(SolutionDir)),以及使用 %VariableName% 来引用环境变量。

                   另,给出一些常用的 【生成命令和属性的宏】

$(ConfigurationName)

当前项目配置的名称(如“Debug”)。

$(PlatformName)

当前项目平台的名称(如“Win32”)。

$(ProjectName)

项目的基本名称。

$(TargetDir)

生成的主输出文件的目录(定义为驱动器 + 路径);包括尾部的反斜杠“\”。

$(TargetName)

生成的主输出文件的基本名称。

$(FrameworkDir)

安装 .NET Framework 的目录。

$(FrameworkVersion)

Visual Studio 使用的 .NET Framework 版本。

$(WebDeployPath)

从 Web 部署根到项目输出所属于的位置的相对路径。返回与RelativePath相同的值。

$(WebDeployRoot)

指向<localhost>位置的绝对路径。例如,c:\inetpub\wwwroot。

 

n  控制块

有三种类型的控制块,根据其左括号对它们进行区分:

1.      <# 标准控制块 #>                            可以包含语句。

2.      <#= 表达式控制块 #>            将一个可以计算为字符串的表达式括起来,用于提供要写入“输出”文件的字符串的代码。

3.      <#+ 类功能控制块 #>            可以使用类功能控制块向文本模板添加方法、属性、字段甚至是嵌套类。必须作为文件中的最后一个块显示,或者用<#@ include #>引入外部文件。

注意:

1)         始终使用 {...}花括号来包含内嵌的嵌套语句,否则会报错。(哪怕花括号中只有一句代码)

2)         控制块不能互相嵌套。必须先终止之前的控制块,然后才能打开另一个。

 

(三)设计时模板和运行时模板

T4文本模板分为:设计时模板和运行时模板

n  添加模板

  1. 设计时模板(文本模板)

优势:当需求变化时,可以根据业务需求调整模型(输入),按照指定规则将“模型”生成任何类型的“文本文件”,例如:网页、资源文件或任何语言的程序源代码。(模型:是描述应用程序特定方面的数据源。它可以是任何形式、任何类型的文件或数据库。如:数据库、配置文件、UML 模型、DSL 模型或其他源)

a)         VS中新建文件——常规——文本模板。(如图)

 

该模板文件中已包含下列指令:

<#@ template debug="false" hostspecific="false" language="C#" #>

<#@ output extension=".txt" #>

b)         或则,添加“纯文本文件”并设置下图属性,加入相关指令。(后缀推荐改为标准的 *.tt)

设计时模板: TextTemplatingFileGenerator

 

  1. 运行时模板(已预处理的文本模板)   

优势:当需求变化时,可以根据业务需求调整模型(输入),在运行时按照指定规则将“模型”生成为“文本字符串”。

  1. VS中新建文件——常规——已预处理的文本模板。

该模板文件包含指令:<#@ template language="C#" #>

  1. 或则,添加“纯文本文件”并设置相应属性,加入相关指令。

运行时模板:TextTemplatingFilePreprocessor

 

n  何时编译,编译过程

  1. 何时编译

在下列任何一种情况下,将执行模板,同时生成附属文件,生成的文件将作为项目的一部分编译。(属性框----生成操作:编译)

1)         编辑模板(模板有异动且没有被保存),当前编辑模板失去焦点。

2)         保存模板。

3)         在“解决方案资源管理器”工具栏中单击“转换所有模板”。转换解决方案中的所有模板。

      

4)         右击“解决方案资源管理器”中的一个或多个模板文件,然后选择“运行自定义工具”。

  1. 编译过程

设计时模板

1)         文本模板转换引擎将“文本模板”转换为可执行的cs代码——“转换类”。转换类(*.cs)存于临时目录下。(临时目录在“环境变量”中设置:右键“我的电脑”—“属性”—“高级系统设置”—“高级”选项卡中“环境变量”—TEMP变量)

命名空间:Microsoft.VisualStudio.TextTemplating + 随机码

基类:Microsoft.VisualStudio.TextTemplating.TextTransformation

类名:GeneratedTextTransformation

 

2)         引擎编译生成的“转换类”生成dll,dll存于临时目录下。具体是哪个dll可以在模板的“调试环境”下使用System.Reflection.Assembly.GetExecutingAssembly();获取。

3)         执行已编译的转换类,生成“文件”。新文件会在“解决方案资源管理器”中出现在文本模板文件下。

 

运行时模板

1)         运行时模板没有<#@ output #>指令,文本模板引擎将“运行时模板”直接编译为cs文件,作为项目的一部分编译。新文件会在“解决方案资源管理器”中出现在文本模板文件下。

命名空间:默认为所属程序集的命名空间

基类:模板文件名 + Base 

类名:模板文件名(PreTextTemplateTest.tt)——注意是“分部类”

 

2)         生成的代码文件随着项目一起编译,并可在应用程序中通过调用生成类中的TransformText() 方法输出“文本字符串”。

 

另外,若要在特定命名空间中放置模板转换生成的类,需设置模板文件的“自定义工具命名空间”属性。

 

  1. 注意事项

1)         控制块使用陷进

TransformText() 方法是由模板引擎将模板中的所有“控制块”代码(包括“包含的模板”)组合生成。所以在使用控制块时应注意以下几点:

a)         语言:只能使用一种语言。

b)         局部变量:确保局部变量的名称不会冲突。

2)         文本模板在单独的AppDomain中运行

请注意,文本模板在与主应用程序分开的AppDomain中运行。在大多数情况下这并不重要,但在某些复杂的情况下您可能会发现一些限制。例如,如果要从单独的服务将数据传入模板或从中传出数据,则该服务必须提供可序列化的 API。

 

(四)技巧

l  快速编写模板

以生成文件为原型,然后逐步插入用于改变结果的控制块。

 

l  T4文本模板的断点调试

  1. 注册表:设置DbgJITDebugLaunchSetting值为 2。

(x86系统): HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\.NETFramework

(x64 系统): HKEY_LOCAL_MACHINE\SOFTWARE\Wow6432Node\Microsoft\.NETFramework

  1. 为template指令添加debug="true"特性:<#@ template debug="true"#>
    1. 命令:

<# System.Diagnostics.Debugger.Launch();#>                  在模板执行到特定点启动调试器。如果用Debugger.Break()启动调试器在调试完后会导致 VS 奔溃。

<#System.Diagnostics.Debugger.Break();#>                     启动调试器后,使用此命令在后续特定点处再次进入调试模式,相当于断点。

使用方法:必须使用“Debugger.Launch()”命令启动调试器(如下图,启动新实例或使用已存在的VS附加。注意,若此处点击取消则将关闭当前IDE),调试完后可以不用中断调试,不影响模板编辑,当再次编译模板时如果存在“Debugger.Break()”命令则自动进入调试模式。

 

 

l  向模板传递参数的两种方法

  1. 使用 <#@ parameter#> 指令引入参数,由模板引擎生成属性访问代码。详细请看 《(译)理解 T4 模板:<#@ parameter #> 指令》 。
  2. 在构造函数中传递参数。只适用于运行时模板,此种模板生成的代码以分部类的形式编写。可以在项目的另一个文件中创建同一个类的其他部分,该文件可以包含一个带参数的构造函数、若干属性和函数,在调用 TransformText() 实例方法前进行初始化。

 

l  使用模板继承共享内容

可以通过编写基类模板(可以是抽象模板)在文本模板之间共享内容。使用<@#template#> 指令的 inherits 特性指定基类。

 

l  运行时调用设计时模板返回字符串

调用 Microsoft.VisualStudio.TextTemplating.Engine 的 ProcessTemplate 方法。

publicstring ProcessTemplate(

     string content,

     ITextTemplatingEngineHost host

)

        content    参数指定文本模板的内容,eg: 使用System.IO.File.ReadAllText(Path) 进行读取

host        参数指定的宿主,必须是实现 ITextTemplatingEngineHost 的类。这是由模板引擎回调的。宿主必须能记录错误、解析对程序集和包含文件的引用、提供可在其中执行模板的应用程序域并为每条指令调用相应的处理器。

 

演练:创建自定义文本模板宿主

 

(五)常用方法

n  模板基类提供的方法

设计时模板继承TextTransformation抽象类

 

 

运行时模板默认继承自动生成的基类

 

  1. Write() 和WriteLine() 方法

写入目的输出文本的三种方式:

a)         文本块

b)         表达式控制块:      <#= 变量 #>

c)         标准控制块:           <# Write() | WriteLine() #>,因为控制块不能嵌套,所以此种方式比<#= 变量 #>书写更优雅。

  1. 输出文本缩进设置

可以使用缩进方法设置文本模板输出的格式。

a)         PushIndent(string indent)         添加指定格式,内部会将字符长度加入到缓存变量indentLengths列表(List<int>)。

b)         PopIndent()                 以“堆栈(先进后出)”形式移除格式,内部按indentLengths列表中存的字符长度进行移除。

c)         ClearIndent()              删除所有缩进。

注意:格式用完后要注意清除,否则可能出现模板中的空行会生成 Write(“\r\n”) 中间代码,最终造成将缩进的格式错误输出到了目的文件。

Eg:

 

  1. 错误报告

若要在 Visual Studio 错误窗口中放置错误消息和警告消息,可以使用以下方法:

<# this.Error("An error message"); #>

<# Warning("A warning message"); #>

 

n  使用执行模板的主机(例如 Visual Studio)公开的方法和属性。这适用于常规文本模板,而不是预处理过的文本模板。

首先,给 template 指令添加hostspecific="true" 特性,以便使用this.Host对象。

(Microsoft.VisualStudio.TextTemplating.ITextTemplatingEngineHost)接口提供方法

 

  1. 使用this.Host.ResolvePath()从相对路径名打开文件
  2. 使用LogErrors() 显示错误消息,如下图:

       

  1. 使用 Visual Studio 中提供的服务(加载EnvDTE.dll )

EnvDTE是組件包裝 COM 程式庫,其中包含了 Visual Studio 核心 Automation 的物件及成員。

引入 EnvDTE.dll 组件后应按下图“属性”进行设置:

 

示例:

<#@ assembly name="EnvDTE" #>

<#

IServiceProvider serviceProvider = (IServiceProvider)this.Host;

EnvDTE.DTEdte = (EnvDTE.DTE) serviceProvider.GetService(typeof(EnvDTE.DTE));

dte.Solution.SaveAs("C:\\backup_Solution");

#>

转载于:https://www.cnblogs.com/TF12138/p/4191484.html

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/376372.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

stdafx.h是什么用处, stdafx.h、stdafx.cpp的作用

http://blog.csdn.net/songkexin/article/details/1750396 stdafx.h头文件的作用 Standard Application Fram Extend没有函数库&#xff0c;只是定义了一些环境参数&#xff0c;使得编译出来的程序能在32位的操作系统环境下运行。Windows和MFC的include文件都非常大&#xff0c…

python3 Connection aborted.', RemoteDisconnected('Remote end closed connection without response'

在写爬虫的时候遇到了问题&#xff0c;网站是asp.net写的 requests.exceptions.ConnectionError: (Connection aborted., RemoteDisconnected(Remote end closed connection without response,)) 于是就抓包分析&#xff0c;发现只要加了’Accept-Language’就好了。。。 A…

id和instancetype的区别

id返回不确定类型的对象&#xff08;也就是任意类型的对象&#xff09;&#xff0c;- (id)arrayWithData;返回的就是不确定类型的对象&#xff0c;如果执行数组的方法&#xff0c; [- (id)arrayWithData objectOfIndex:0]编译时不会报错&#xff0c;但运行时会报错&#xff0c;…

windows下Java 用idea连接MySQL数据库

Java用idea连接数据库特别简单。 首先就是下载好MySQL数据库的驱动程序。 链接&#xff1a;https://dev.mysql.com/downloads/connector/j/ 然后就是选下载版本了&#xff1a; 选个zip格式的嘛。。 下载完后就解压。打开idea&#xff0c;建立个简单的项目 找到这个: …

7-2

#include<stdio.h> int main(void) {int i;int fib[10]{1,1};for(i2;i<10;i)fib[i]fib[i-1]fib[i-2];for(i0;i<10;i){printf("%6d",fib[i]);if((i1)%50)printf("\n");}return 0; } 转载于:https://www.cnblogs.com/liruijia199531/p/3357481.h…

岁月悄然前行,没有停留的痕迹

岁月悄然前行&#xff0c;没有停留的痕迹。月落乌啼&#xff0c;总是千年的风霜;涛声依旧&#xff0c;不见当初的夜晚。走过岁月的痕迹&#xff0c;已是物是人非。我们在岁月的轨道上行走&#xff0c;不要给岁月太多的装饰&#xff0c;不要给岁月太多的言语。给它我们随着时光追…

160 - 41 defiler.1.exe

环境&#xff1a; Windows xp sp3 工具&#xff1a; Ollydbg stud_PE LoadPE 先分析一下。 这次的程序要求更改了&#xff0c;变成了这个&#xff1a; defilers reversme no.1 -----------------------The task of this little, lame reverseme is to add some code to…

HDU-2112 HDU Today

http://acm.hdu.edu.cn/showproblem.php?pid2112 怎样把具体的字母的地点转换为数字的函数为题目的重点。 HDU Today Time Limit: 15000/5000 MS (Java/Others) Memory Limit: 32768/32768 K (Java/Others) Total Submission(s): 11385 Accepted Submission(s): 2663 P…

AndEngine引擎之SmoothCamera 平滑摄像机

SmoothCamera:就相当于现实世界的摄像机&#xff0c;要想照到一个物体&#xff0c;要么是摄像机移动&#xff0c;要么是物体移动到摄像头的范围内&#xff0c;想要放大或缩小一个物体&#xff0c;要么是物体向前或向后移动&#xff0c;要么是摄像头变焦 这里讨论的就是摄像头的…

160 - 44 defiler.1.exe

环境&#xff1a; Windows xp sp3 工具&#xff1a; 1.ollydbg 2.exeinfope 0x00 查壳 无壳就下一步 0x01 分析 随便输入个错的&#xff0c;出现了不知道哪国的语言。有个6&#xff0c;应该就是name的长度要大于6吧 OD载入&#xff0c;搜字符串。 00421BD7 |. 807D…

时间与日期处理

主要有以下类&#xff1a; NSDate -- 表示一个绝对的时间点NSTimeZone -- 时区信息NSLocale -- 本地化信息NSDateComponents -- 一个封装了具体年月日、时秒分、周、季度等的类NSCalendar -- 日历类&#xff0c;它提供了大部分的日期计算接口&#xff0c;并且允许您在NSDate和N…

C++ new/new operator、operator new、placement new初识

简要释义 1.operator new是内存分配函数&#xff08;同malloc&#xff09;&#xff0c;C&#xff0b;&#xff0b;在全局作用域(global scope)内提供了3份默认的operator new实现&#xff0c;并且用户可以重载operator new。 1 void* operator new(std::size_t) throw(std::bad…

160 - 45 Dope2112.2

环境&#xff1a; Windows xp sp3 工具 1.ollydbg 2.exeinfope 0x00 查壳 还是无壳的Delphi程序 0x01 分析 这次继续OD载入搜字符串&#xff0c;但是没找到错误信息的字符串。 又因为是Delphi程序&#xff0c;所以可以试一下这样&#xff1a; OD载入后还是搜字符串&…

编辑技巧 word

怎样给word中的文档加上水印 转载于:https://www.cnblogs.com/dqxu/p/4208372.html

NAT地址转换原理全攻略

NAT转换方式及原理 在NAT的应用中&#xff0c;可以仅需要转换内部地址&#xff08;就是“内部本地址”转换成“内部全局地址”&#xff09;&#xff0c;这是最典型的应用&#xff0c;如内部网络用户通过NAT转换共享上网&#xff1b;也可以是仅需要转换外部地址&#xff08;就是…

通过setTimeout来取消因大量计算造成的网页卡顿

js是单线程的&#xff0c;所以有些大量计算的操作会占用线程资源&#xff0c;导致页面卡住。 今天遇到这样一个场景&#xff0c;选择一个下拉框之后&#xff0c;对数据进行筛选&#xff0c;这个过程中有大量计算&#xff0c;点了selecte的option之后&#xff0c;option不隐藏&a…

160 - 47 DueList.2

环境&#xff1a; Windows xp sp3 工具&#xff1a; Ollydbg exeinfope 0x00 查壳 无壳的程序 0x01 分析 运行后说需要keyfile&#xff0c;那就创建一个。 OD载入找找看需要的keyfile叫什么名字 00401000 > $ 6A 00 push 0x0 …

如何解决Visual Studio2012 与此版本的Windows不兼容

解决方案&#xff1a; http://www.microsoft.com/zh-CN/download/details.aspx?id36020 下载更新转载于:https://www.cnblogs.com/awodefeng/p/3373343.html

160 - 48 DueList.3

环境&#xff1a; Windows xp sp3 工具&#xff1a; Ollydbg exeinfope 0x00 查壳 无壳的程序 0x01 分析 应该就是选上某个或多个框后点Check就能成功的&#xff0c;那应该就是不同框对应不同的值咯。旁边还有个提示&#xff1a;建议使用资源编辑器。 直接OD载入&#x…

为什么django+mongo在windows上session能够获取到,同样的程序在linux上就会报session的变量错误,keyerror?...

settings&#xff1a;SESSION_ENGINE django.contrib.sessions.backends.cache 其它地方&#xff1a;正常存取值。request.session["mm"]“MM” 转载于:https://www.cnblogs.com/angelfeeling/p/4211261.html