[转]T4模版引擎之基础入门

本文转自:http://www.cnblogs.com/lzrabbit/archive/2012/07/15/2591085.html

 额,T4好陌生的名字,和NuGet一样很悲催,不为世人所熟知,却又在背后默默无闻的奉献着,直到现在我们项目组的人除了我之外,其它人还是对其豪无兴趣,基本上是连看一眼都懒得看,可怜的娃啊。。。

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

  在学习枯燥的概念前我们先来看一下用T4模版快速生成POCO实体类的示例
打开VS2010建一个项目,然后右击项目文件选择新建项,在文件列表中找到文件模版,如图所示

修改TextTemplate1.tt文件内容如下

复制代码
<#@ template debug="false" hostspecific="false" language="C#" #>
<#@ output extension=".cs" #>
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;namespace ConsoleApplication1
{    public class User{/// <summary>/// 用户ID/// </summary>public int UserID { get; set; }/// <summary>/// 用户名/// </summary>public string UserName { get; set; }/// <summary>/// 密码/// </summary>public string Password { get; set; }/// <summary>/// Email/// </summary>public string Email { get; set; }/// <summary>/// 手机号/// </summary>public string Mobile { get; set; }}
}
复制代码

点击Ctrl+S然后可以看到自动生成了一个TextTemplate1.cs文件

复制代码
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;namespace ConsoleApplication1
{    public class User{/// <summary>/// 用户ID/// </summary>public int UserID { get; set; }/// <summary>/// 用户名/// </summary>public string UserName { get; set; }/// <summary>/// 密码/// </summary>public string Password { get; set; }/// <summary>/// Email/// </summary>public string Email { get; set; }/// <summary>/// 手机号/// </summary>public string Mobile { get; set; }}
}
复制代码

是不是很神奇,T4模版引擎会根据你在模版里定义的内容自动生成相应的文件,当然本示例过于简单,完全不能展现T4的强大,当你若真正了解T4后,会发现神马代码生成器全都是浮云,T4才是王道,利用T4你完全可以轻松生成属于自己风格的任何类型代码,在下篇文章会有实例展示如何通过T4连接数据库自动生成POCO类,基本上这个才是我们用T4的最大意图,呵呵,在这之前还是老老实实看看枯燥乏味的T4基础知识吧。

T4 文本模板有两种类型:设计时 T4 文本模板运行时 T4 文本模板(“预处理过的”模板)

  • 设计时模版

  可在应用程序中执行运行时 T4 文本模板(“预处理过的”模板)以便生成文本字符串(通常作为其输出的一部分)。

  若要创建运行时模板,请向您的项目中添加“已预处理的文本模板”文件。 另外,您还可以添加纯文本文件并将其“自定义工具”属性设置为“TextTemplatingFilePreprocessor”

  有关更多信息,请参见使用预处理 T4 文本模板生成运行时文本。 有关模板语法的更多信息,请参见编写 T4 文本模板。

  • 运行时模版

  在 Visual Studio 中执行设计时 T4 文本模板,以便定义应用程序的部分源代码和其他资源。

  通常,您可以使用读取单个输入文件或数据库中的数据的多个模板,并生成一些 .cs.vb 或其他源文件。 每个模板都生成一个文件。 在 Visual Studio 或 MSBuild 内执行它们。

  若要创建设计时模板,请向您的项目中添加“文本模板”文件。 另外,您还可以添加纯文本文件并将其“自定义工具”属性设置为“TextTemplatingFileGenerator”

  有关更多信息,请参见使用 T4 文本模板生成设计时代码。 有关模板语法的更多信息,请参见编写 T4 文本模板。 

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

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

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

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

T4 文本模板指令

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

     顾名思义,就是用来传参的,应该是用在运行时模版的(预处理模版)

  • T4 输出指令
    <#@ output extension=".fileNameExtension" [encoding="encoding"] #>

    比较重要的指令,用于设置输出文件的后缀名和文件编码
    extension:输出文件扩展名,默认为".cs"
    encoding:文件编码,默值为utf-8(这里不能确定,我测试是utf-8)

  • 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、WindowsBase.dll,如果用到了其它的程序集需要显示的使用程序集添加引用才可以
  4. 可以使用 $(variableName) 语法引用 Visual Studio 或 MSBuild 变量(如 $(SolutionDir)),以及使用 %VariableName% 来引用环境变量。介绍几个常用的$(variableName) 变量:

    $(SolutionDir):当前项目所在解决方案目录

    $(ProjectDir):当前项目所在目录

    $(TargetPath):当前项目编译输出文件绝对路径

    $(TargetDir):当前项目编译输出目录,即web项目的Bin目录,控制台、类库项目bin目录下的debug或release目录(取决于当前的编译模式)

    举个例子:比如我们在D盘根目录建立了一个控制台项目TestConsole,解决方案目录为D:\LzrabbitRabbit,项目目录为
    D:\LzrabbitRabbit\TestConsole,那么此时在Debug编译模式下
    $(SolutionDir)的值为D:\LzrabbitRabbit
    $(ProjectDir)的值为D:\LzrabbitRabbit\TestConsole
    $(TargetPath)值为D:\LzrabbitRabbit\TestConsole\bin\Debug\TestConsole.exe
    $(TargetDir)值为D:\LzrabbitRabbit\TestConsole\bin\Debug\

  • T4 导入指令
    <#@ import namespace="namespace" #>

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

  • 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文件,里面包含了我们平时常用的程序集引用
    复制代码
    <#@ assembly name="System.Core.dll" #>
    <#@ assembly name="System.Data.dll" #>
    <#@ assembly name="System.Data.DataSetExtensions.dll" #>
    <#@ assembly name="System.Xml.dll" #>
    <#@ import namespace="System" #>
    <#@ import namespace="System.Xml" #>
    <#@ import namespace="System.Linq" #>
    <#@ import namespace="System.Data" #>
    <#@ import namespace="System.Data.SqlClient" #>
    <#@ import namespace="System.Collections.Generic" #>
    <#@ import namespace="System.IO" #>
    复制代码

    使用时只需要使用包含指令引用下即可

    <#@ include file="$(ProjectDir)Reference.ttinclude"  #>

文本块

文本块直接向输出文件插入文本。 文本块没有特殊格式。 例如,下面的文本模板将生成一个包含单词“Hello World!”的文本文件:

<#@ output extension=".txt" #>
Hello World! 

控制块 

控制块是用于转换模板的程序代码节。 默认语言是 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 #>.
<#   
}
#>
复制代码

将文本生成方法放置在可供多个模板包含的单独文件中,是非常有用的。

嗯,大概的基础点应该就这些了,更多的自己去MSDNhttp://msdn.microsoft.com/zh-cn/library/bb126445详细了解吧

  这里解释点容易让人困惑的地方,我们在T4模版里面引用的程序集和那些命名空间都是利用T4生成代码需要使用的,也就是T4模版要用的,和我们要生成的目标类毛关系都没有,当初为搞清楚这点可是费了不精力。T4初看起来很复杂,其实稍微花些心思研究下,主要似乎把MSDN看懂还是很容易学会的,一旦掌握了受用无穷

#6楼 2012-07-16 11:04 sdf333
有好的T4编辑器吗?现在纯文本写T4很蛋疼
#7楼[楼主] 2012-07-16 11:12 懒惰的肥兔
我现在用T4 Editor,有代码着色和简单的智能提示,一般够用了

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

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

相关文章

请问WCF 跟 WebService之间异同

From: http://tommyhu.cn/wcf-WebService-qu-bie/ 问题&#xff1a; WCF与 Web Service的区别是什么&#xff1f; 和ASP.NET Web Service有什么关系&#xff1f; WCF与ASP.NET Web Service的区别是什么&#xff1f; 这是很多.NET开发人员容易搞错的问题。面试的时候也经常遇到…

报错 Cannot read properties of undefined (reading ‘ajax‘); Cannot read property ‘ajax‘ of undefined

jQuery中使用ajax发送请求&#xff0c;报错 Cannot read properties of undefined (reading ajax)&#xff1b; Cannot read property ajax of undefined 错误代码 $.ajax({type:"POST",url:"pageServlet",data:jsonData,dataType:"json",succe…

「初步」Spring与commons的BeanUtil.copyProperties

2019独角兽企业重金招聘Python工程师标准>>> ###org.apache.commons.beanutils.BeanUtils 的是 public static void copyProperties(Object dest, Object orig) throws###org.​springframework.​beans.​BeanUtils 的是 public static void copyProperties(Object…

WCF技术剖析之十一:异步操作在WCF中的应用(上篇)

From: http://www.cnblogs.com/artech/archive/2009/07/08/1519423.html 按照操作执行所需的资源类型&#xff0c;我们可以将操作分为CPU绑定型&#xff08;CPU Bound&#xff09;操作和I/O绑定型&#xff08;I/O Bound&#xff09;操作。对于前者&#xff0c;操作的执行主要利…

vue2使用vant组件库;使用rem后vant组件样式变小了。

vue2使用vant组件库 文章目录vue2使用vant组件库一、vant是什么&#xff1f;二、使用步骤1.引入vant2库2.引入 自动按需引入组件3.在main.js中按需引入组件&#xff08;推荐&#xff09;4.或者只是在某个index.vue内使用&#xff08;推荐&#xff09;5.在main.js中导入所以组件…

EditPlus自定义模板

直接用图表达了,不详之处可以留言. 1.查看帮助中的关于,确定文本编辑器的版本是否一致 2.如图 3.如图 4.这个test.html 需要事先编辑并拷贝到EditPlus的安装目录 5.新建空白html 时,效果如下: 6.方便大家,代码贴上来. html> <head> <title>网页标题…

【Android】Android开发启动app弹出一张广告图片,Dialog可以查看大图,查看某个图片功能...

作者&#xff1a;程序员小冰&#xff0c;GitHub主页&#xff1a;https://github.com/QQ986945193 新浪微博&#xff1a;http://weibo.com/mcxiaobing 首先给大家看一下我们今天这个最终实现的效果图&#xff1a; 首先说一下&#xff0c;这里利用的是一个dialog&#xff0c;然…

el-dialog弹框中img图片保持比例最大化;图片保持比例最大化

图片保持比例最大化 <el-dialog :visible.sync"dialogVisible" center class"look_img_dia"><img width"100%" :src"dialogImageUrl" alt"" /></el-dialog>.look_img_dia {/deep/.el-dialog {margin-top…

Wireshark技巧-过滤规则和显示规则

From: http://www.cnblogs.com/icez/p/3973873.html Wireshark是一个强大的网络协议分析软件&#xff0c;最重要的它是免费软件。 过滤规则 只抓取符合条件的包&#xff0c;在Wireshark通过winpacp抓包时可以过滤掉不符合条件的包&#xff0c;提高我们的分析效率。 如果要填写过…

easyUI 展开DataGrid里面的行显示详细信息

http://blog.csdn.net/yanghongchang_/article/details/7854156原著 datagrid 可以改变它的view(视图)去显示不同的效果.使用详细视图,datagrid可以显示展开按钮("" 或者 "-")在数据行的左边,用户可以展开一个行去显示一个附加的详细信息. 查看 Demo 步骤 …

理解OAuth 2.0(转)

From: http://www.mamicode.com/info-detail-1610036.html 理解OAuth 2.0 作者&#xff1a; 阮一峰 日期&#xff1a; 2014年5月12日 OAuth是一个关于授权&#xff08;authorization&#xff09;的开放网络标准&#xff0c;在全世界得到广泛应用&#xff0c;目前的版本是2.0版。…

wcf返回datatable必须给tablename赋值

From: http://www.cnblogs.com/hxw/archive/2010/07/10/1774841.html 最近在学习WCF,返回datatable的时候老是出现“An error occurred while receiving the HTTP response to http://localhost:9999/calculatorservice. This could be due to the service endpoint binding no…

微信支付开发(1) JS API支付

From: http://www.cnblogs.com/txw1958/p/wxpayv3-jsapi.html 关键字&#xff1a;微信支付 微信支付v3 jsapi支付 统一支付 Native支付 prepay_id 作者&#xff1a;方倍工作室 原文: http://www.cnblogs.com/txw1958/p/wxpayv3-jsapi.html 本文介绍微信支付下的jsapi实现流程…

el-upload多文件上传;el-upload采用递归依次上传文件;el-upload采用递归在上一个文件上传成功后再传下一个文件

场景&#xff1a; 需求是接口一次上传一个文件&#xff0c;前一个文件上传成功后再调下一个接口上传下一个文件。 el-upload本身就支持多文件上传。但是它是并发进行&#xff0c;例如&#xff1a;选择一千个文件后&#xff0c;是一千个文件自动立马并行调用一千个后端接口去上传…

Controller向View传值方式总结

From: http://www.cnblogs.com/guohu/p/4377974.html 总结发现ASP.NET MVC中Controller向View传值的方式共有6种&#xff0c;分别是&#xff1a; ViewBagViewDataTempData向普通View页面传一个Model对象向强类型页面传传一个Model对象用一个ViewModel对象解决所有问题 首先我们…

记录一次bug解决过程:数据迁移

一 总结不擅长语言表达&#xff0c;勤于沟通&#xff0c;多锻炼 调试MyBatis中SQL语法:foreach 问题&#xff1b;缺少关键字VALUES。很遗憾&#xff1a;它的错误报的让人找不着北。 二 BUG描述&#xff1a;MyBatis中批量插入数据异常 <?xml version"1.0" encodin…

繁华模拟赛 ljw分雕塑

/* 用f[i][k]表示考虑到第i个雕塑&#xff0c;分成k组&#xff0c;可不可行&#xff08;这是一个bool类型的数组&#xff09; 转移&#xff1a; f[i][k]f[j][k-1],sum[i]-sum[j]合法 */ #include <cstdio> #include <cstdlib> #include <cstring> #include &…

Razor语法大全

From: http://www.cnblogs.com/dengxinglin/p/3352078.html Razor是基于framewor4以上写的一个开源项目&#xff1a;https://github.com/Antaris/RazorEngine/ Razor是包含了模板引擎和动态编译两部分。本部分就简单记录了模板引擎的一些语法&#xff0c;之后用Razor做一个代码…

el-dialog的内容不刷新;el-dialog内容有缓存;el-dialog里面的组件不刷新问题;

el-dialog里面的内容是带缓存的&#xff0c;也就是说除了第一次打开会初始化&#xff0c;其他次打开都是直接加载缓存的&#xff1b; 这就导致了有时候打开弹框时候&#xff0c;内容不刷新。有说法说是el-dialog嵌套太深大致的。 解决方法&#xff1a;直接给弹框的内容部分添加…

el-badge标记;el-tabs配合el-badge提示数字

标签选项卡配个标记数字提示 注意&#xff1a;el-tabs可以通过具名 slot 来实现选项卡的内容 <template><div><el-tabs v-model"tabValue"><el-tab-pane label"全部" name"1"></el-tab-pane><el-tab-pane lab…