Text Template Transformation Toolkit

1.且算简介

笔者以一个英文字母和一个数字取了一个简单的名字。名唤"T4"(名字太短,不易点,体验不好,已修改)。

也许你会好奇,想着T4何也?然后轻击鼠标,点开。亦或您知道,只是想看看,您或轻或重的点击鼠标,打开。

笔者这里写的T4是指“T4文本模板”。它是微软自家产的。一个基于模板的代码生成器。它由文本块和控制逻辑块组成的一个模板,可以自动的生成一些文本。有点类似于动软或者Code Smith,只是笔者认为它可比动软或者Code Smith优秀些。,毕竟它是微软自己家的。

那也许您也会问,为什么叫“T4”也不是“T3”或者“M2”什么的呢?

这是因为它的因为全称是Text Template Transformation Toolkit。它的全称的四个单词的首字母全部是以T开头的,故尔得此名。

那么用它有什么好处呢?

它可以快速的为我们生成一些代码,节省我们的时间。加快开发效率。比如笔者曾经写过一篇博文,讲的是不写代码只要点几点就可以生成一个实体类的CRUD(此文受到了争议,笔者当时只是想做到的是,如若你不知道可以这样,那么你看到了我这样了,那么你也许会感点兴趣,然后仔细研究一下里面的详细代码什么的,此是初衷,不再解释),那么这里面的控制器的代码和视图的代码,勿庸置疑,亦是用到了T4模板。或者我们用EF映射了一个实体的时候,那么此实体的edmx的下面也是有一个由tt结尾的文件也是T4模板,我们如若开始学的时候也可以看一下这个里面的代码,正如我的那篇点点点。

2.且举个好吃(简单易懂)的栗子

我们新建一个控制台的项目。然后在此项目上加一个文本模板的选项,名叫“TestTemplateDemo”。如图:

那么会生成这样的一个文件,里面已有的代码如下:

此原本已有的代码可以认为是指令块。比如程序集指令,导入指令,输入指令(至于哪一行属于什么指令,读者自己判断)。

另外T4模板还可以有文本块和控制块。文本块,可以认为是1+1=2,很简单,也就是使输入指令为.txt,然后再下面输入一个纯的文本也就是了(笔者是这么认为的,不知对否)。

控制块就是我们在项目中会用到的,也就是里面写一些语言,比如C#,最后C#的代码会运行输出(依旧笔者个人理解,官方解释就不找了,官方写的都比较难懂)。

 1 <#@ template debug="false" hostspecific="false" language="C#" #>
 2 <#@ assembly name="System.Core" #>
 3 <#@ import namespace="System.Linq" #>
 4 <#@ import namespace="System.Text" #>
 5 <#@ import namespace="System.Collections.Generic" #>
 6 <#@ output extension=".cs" #>
 7
 8 public  class  Samsung
 9 {
10    <# for(int i=1;i<5;i++)    {#>
11           public string S<#=i#>{get;set;}
12           <#}#>
13 }

写一下控制块的代码

我们CTRL+S一下,打开tt下面的cs文件,看一下我们的三星旗舰:

1 public  class   Samsung
2 {
3            public string S1{ get; set;}
4            public string S2{ get; set;}
5            public string S3{ get; set;}
6            public string S4{ get; set;}
7 }

看一下三星的旗舰

是的,三星万年不变大塑料机是由T4模板自动帮我们生成的。其模板内代码写法不解释,跟MVC的ASPX引擎没什么两样。

好吧,笔者真心不太喜欢三星的大塑料,要不换成魅族的梦想可好。嗯,好吧,就当检测一下T4模板也是好的。

 1 <#@ template debug="false" hostspecific="false" language="C#" #>
 2 <#@ assembly name="System.Core" #>
 3 <#@ import namespace="System.Linq" #>
 4 <#@ import namespace="System.Text" #>
 5 <#@ import namespace="System.Collections.Generic" #>
 6 <#@ output extension=".cs" #>
 7
 8 public  class  Meizu
 9 {
10    <# for(int i=1;i<5;i++)    {#>
11           public string MX<#=i#>{get;set;}
12           <#}#>
13 }

修改下控制块代码,我想要梦想

CTRL+S,看一下梦想之作:

1 public  class   Meizu
2 {
3            public string MX1{ get; set;}
4             public string MX2{ get; set;}
5             public string MX3{ get; set;}
6             public string MX4{ get; set;}
7  }

且容我看一眼梦想。

那么T4是有点帅,还是很有点帅。

那么很有点帅,或者相当帅吧。

3.且再举一个栗子(来自实际项目)

此"栗子",可能是比上面略复杂一点,来源于实际项目中,相信仔细咀嚼味道还是鲜美的。

我一个项目中有数据访问接口层,访问接口层(IBaseDal)要用来约束访问,比如约定了其类型是一个泛型T类型的且其有一个默认的构造函数。一个实现了IBaseDal接口的IUserDal。访问层(BaseDal)主要用来封装一些实体的公共方法,其实现IBaseDal。下面还有实现和继承了访问层以及实现了数据接口层的UserDal。其关系可见下面代码。至于UML类图,感兴趣的朋友可以自己画一下,本是打处用笔在纸上画好然后,然后拍照示意之。不过笔者手机出问题了,也不想用其他方式弄了,此处也就省略了。

 1 using System;
 2 using System.Collections.Generic;
 3 using System.Linq;
 4 using System.Text;
 5 using System.Threading.Tasks;
 6
 7 namespace Anmutu.OA.IDAL
 8 {
 9     /// <summary>
10     /// 此接口抽象了DAL实例里公共方法的约束。
11     /// </summary>
12    public  interface IBaseDal<T> where T: class, new ()
13     {
14         T Add(T entity);
15         bool Update(T entity);
16         bool Delete(T entity);
17         int Delete( params int[] ids);
18     }
19 }

IBaseDal

 1 using System;
 2 using System.Collections.Generic;
 3 using System.ComponentModel;
 4 using System.Linq;
 5 using System.Text;
 6 using System.Threading.Tasks;
 7 using Anmutu.OA.Model;
 8
 9 namespace Anmutu.OA.IDAL
10 {
11     /// <summary>
12     /// 创建一个接口,约定其返回类型是User类,参数是一个user实体。
13     /// </summary>
14     public  interface IUserDal:IBaseDal<User>
15     {
16
17      }
18 }

IUserDal

 1 using System;
 2 using System.Collections.Generic;
 3 using System.Data;
 4 using System.Data.Entity;
 5 using System.Linq;
 6 using System.Text;
 7 using System.Threading.Tasks;
 8 using Anmutu.OA.Model;
 9 using EntityState = System.Data.Entity.EntityState;
10
11 namespace Anmutu.OA.DAL
12 {
13     /// <summary>
14     /// 把数据库访问层的公共方法抽出来实现。
15     /// </summary>
16     /// <typeparam name="T"></typeparam>
17    public particl class BaseDal<T> where T: class, new() //类。且有一个默认的构造函数。
18     {
19        //写在这里就没做到线程实例唯一了。此处亦就用简单工厂得到上下文实例。
20        private Model.AnmutuModelContainer db = new AnmutuModelContainer();
21         public T Add(T entity)
22         {
23             db.Set<T>().Add(entity);
24             db.SaveChanges();
25              return entity;
26         }
27
28         public bool Update(T entity)
29         {
30             db.Entry(entity).State = EntityState.Modified;
31             return db.SaveChanges() > 0;
32         }
33
34         public bool Delete(T entity)
35         {
36             db.Entry(entity).State = EntityState.Deleted;
37             return db.SaveChanges() > 0;
38         }
39
40         public int Delete( params int[] ids)
41         {
42             foreach ( var id in ids)
43             {
44                 //如若实体已经在内存中就在内存中拿,如果内存中没有则查询数据库。
45                 var entity = db.Set<T>().Find(id);
46                 db.Set<T>().Remove(entity);
47             }
48          return   db.SaveChanges();
49         }
50     }
51 }

BaseDal

 1 using System;
 2 using System.Collections.Generic;
 3 using System.Data;
 4 using System.Linq;
 5 using System.Text;
 6 using System.Threading.Tasks;
 7 using Anmutu.OA.IDAL;
 8 using Anmutu.OA.Model;
 9 using EntityState = System.Data.Entity.EntityState;
10
11 namespace Anmutu.OA.DAL
12 {
13     public partial class UserDal : BaseDal<User>,IUserDal //这里实现接口。
14     {
15
16     }
17 }

UserDal

笔者注:其中有代码少了PARTICAL关键字,如若改兴趣,你会发现是哪里的,笔者就不回去做修改了。

我们很显然的就可以看出来。如若我们要再加一个Role实体的话,它理应有这些公共的方法。而按照此数据访问层的写法的话,我们可能就得写很多类似的代码了。很多地方相应的User改变成Role,也就可以了。那么T4隆重出场了(笔者在这里写了四个,是为表示很多地方都可以用到T4,示例只写一个)。

 1 <#@ template language="C#" debug="false" hostspecific="true"#>
 2 <#@ include file="EF.Utility.CS.ttinclude"#>
 3 <#@ output extension=".cs"#>
 4
 5 <#
 6 CodeGenerationTools code = new CodeGenerationTools(this);
 7 MetadataLoader loader = new MetadataLoader(this);
 8 CodeRegion region = new CodeRegion(this, 1);
 9 MetadataTools ef = new MetadataTools(this);
10
11 string inputFile = @"..\\Anmutu.OA.Model\\AumutuModel.edmx";
12 EdmItemCollection ItemCollection = loader.CreateEdmItemCollection(inputFile);
13 string namespaceName = code.VsNamespaceSuggestion();
14 EntityFrameworkTemplateFileManager fileManager = EntityFrameworkTemplateFileManager.Create(this);
15 #>
16
17 using System;
18 using System.Collections.Generic;
19 using System.Data;
20 using System.Linq;
21 using System.Text;
22 using System.Threading.Tasks;
23 using Anmutu.OA.IDAL;
24 using Anmutu.OA.Model;
25 using EntityState = System.Data.Entity.EntityState;
26
27 namespace Anmutu.OA.DAL
28 {
29 <#
30 foreach (EntityType entity in ItemCollection.GetItems<EntityType>().OrderBy(e => e.Name))
31     {
32   #>
33      public partial class <#=entity.Name#>Dal : I<#=entity.Name#>Dal
34          {
35
36           }
37 <#}#>
38 }

IUserDal的T4

那么,这样当你有实体且已保存的时候,你只需要在此处CTRL+S一下,数据访问接口层(IBaseDal与IUserDal)的代码也就自动为你生成好了。至于在上面这四个地方的其他地方,同样可以采用到T4模板自动相应生成。当然一个比较好的框架的话,不仅DAL层会有相应的可以通过T4就可以相应生成代码的。BLL层或者UI层也是可以有的,或者是各种层中的工厂。我们都可以相对应的写T4。然后,我们保存就会自动为我们生成相应的代码了。生成后,自然会有各自对象,我们就可以直接拿来用了。

只是当我新增一个实体后且已保存了。且算DAL层有4个T4,BLL层也有4个T4,那我都得打开一遍,然后CTRL+S,才会为我们生成相应的代码,这样也慢了一点。

至于这个嘛,你可以点击VS上“生成(BUILD)”中会有一个“转换所有T4模板(Transform All T4 Templates)”。VS则会自动的帮你重新保存一下所有的T4,也自然会自动帮我们生成各种层之间的各个T4,不用我们打开每个去保存。那么,现在假设你新增一个实体已保存且每个层中的T4模板均已写好。你想快速的去操作这个实体,那么,你做的只是需要点两下就可以去操作此实体了。那些DAL层中的IDAL或者DAL,BLL层的IBLL或者BLL,亦或是各种工厂,那些代码,根本就不需要你写。所以,由此看T4是可以帮助我们提高开发效率的。

如此看来上面的那个“栗子”算不得相当帅,这个倒时可以算的。

笔者初探T4,如若有不对之处,还请斧正。谢。

时间: 2024-12-17 23:24:43

Text Template Transformation Toolkit的相关文章

C# Meta Programming - Let Your Code Generate Code - Introduction of The Text Template Transformation Toolkit(T4)

<#@ template language="C#" #> <#@ output extension=".cs" #> <#@ assembly name="System.Core" #> <#@ import namespace="System.Linq" #> <# Type[] types_to_generate = new[] { typeof(object), t

&lt;script type=&quot;text/template&quot;&gt;是干什么的,为什么要把html写在js中? 这是什么编程语言风格,都能这样用吗?

这一段存放了一个模板.在js里面,经常需要使用js往页面中插入html内容.比如这样: var number = 123; $('#d').append('<div class="t">'+number+'</div>') 如果html很短还好说,但是遇到描述里面的这么大段,直接用字符串存储会很困难,因为不光要处理单引号,还需要很多「+」号把字符串一个个连接起来,十分的不方便.给<script>设置type="text/template&q

关于MVC模板渲染的一点小事type=&quot;text/template&quot;

先上一个demo,简单粗暴,请自便 <!DOCTYPE html> <html> <head lang="en"> <meta charset="UTF-8"> <title></title> <style> *{ margin: 0px; padding: 0px; } </style> <script src="http://code.jquery.c

go text/template html/template invalid memory address or nil pointer dereference

2017/08/14 20:06:10 http: panic serving 172.22.27.131:56324: runtime error: invalid memory address or nil pointer dereference goroutine 19 [running]: net/http.(*conn).serve.func1(0xc420171e00) /usr/local/go/src/net/http/server.go:1693 +0xd0 panic(0x7

&lt;script type=&quot;text/template&quot;&gt;

<script type="text/template"> 给<script>设置type="text/template",标签里面的内容不会被执行,也不会显示在页面上,但是可以在另一个script里面通过获取,然后再通过相关的模板工具进行处理,插入到页面中.这样就把大段的HTML操作从js里面分离开了 <div></div> <script type="text/template" id=&

排球计分程序重构(一)

前言: 上学期制作的排球计分程序,本次重构主要进行了一些功能性的完善,能够查询队伍比分,以及计分精确到队员. 已经将网站发布到我的服务器上面可以浏览 http://www.colorfulhy520.top:82/Home/Index 进入正题: 初步计划将文章系列分为以下几篇: 1.综述 2.数据库设计 3.Controller和View设计 4.代码讲解 5.总结 运用到的技术 1.Petapoco PetaPoco是一款适用于.NET应用程序的轻型对象关系映射器(ORM, Object R

T4模板:T4模板之菜鸟篇

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

实体框架6.0(Recipes)翻译系列 1 -----第一章 开始使用实体框架1

微软的Entity Framework 受到越来越多人的关注和使用,Entity Framework7.0版本也即将发行.虽然已经开源,可遗憾的是,国内没有关于它的书籍,更不用说好书了,可能是因为EF版本更新太快,没人愿意去花时间翻译国外关于EF的书籍.使用Entity Framework开发已经有3年多了,但用得很肤浅,最近想深入学习,只好找来英文书<Entity Framework 6 Recipes>慢慢啃.首先需要说明的是,我英文不好,只是为了学习EF.把学习的过程写成博客,一是督促自

Entity Framework 1

-----------------------19:15 2015/1/31 EF----------------------------------- EF5.0利用Entity Framework,开发人员可以使用.NET对象和语言集成查询(LINQ)对关系数据库进行编程.它具有多项新功能,包括持久性忽略和POCO支持 ,外键关联,延迟加载,测试驱动开发支持,模型中的函数和新的LINQ运算符.其他功能包括:带自跟踪实体的更好的N层支持.使用T4模板的可自定义 的代码生成,模型首次开发,改进的