T4随记
关于T4模板的信息我就不赘述了,百度一大堆
MSDN的介绍 https://msdn.microsoft.com/zh-cn/library/bb126478.aspx
下面是简单的一个示例,从类中获取字符串数组,并生成数组相应的类文件
需要一个MultipleOutputHelper.ttinclude文件,你也可以百度下载,
新建一个模板文件,重命名为MultipleOutputHelper.ttinclude,然后写入如下内容,不需要任何修改
<#@ assembly name="System.Core"
#><#@ assembly name="System.Data.Linq"
#><#@ assembly name="EnvDTE"
#><#@ assembly name="System.Xml"
#><#@ assembly name="System.Xml.Linq"
#><#@ import namespace="System.Collections.Generic"
#><#@ import namespace="System.IO"
#><#@ import namespace="System.Text"
#><#@ import namespace="Microsoft.VisualStudio.TextTemplating"
#><#+
// https://raw.github.com/damieng/DamienGKit
// http://damieng.com/blog/2009/11/06/multiple-outputs-from-t4-made-easy-revisited // Manager class records the various blocks so it can split them up
class Manager {
private class Block {
public String Name;
public int Start, Length;
public bool IncludeInDefault;
} private Block currentBlock;
private readonly List<Block> files = new List<Block>();
private readonly Block footer = new Block();
private readonly Block header = new Block();
private readonly ITextTemplatingEngineHost host;
private readonly StringBuilder template;
protected readonly List<String> generatedFileNames = new List<String>(); public static Manager Create(ITextTemplatingEngineHost host, StringBuilder template) {
return (host is IServiceProvider) ? new VSManager(host, template) : new Manager(host, template);
} public void StartNewFile(String name) {
if (name == null)
throw new ArgumentNullException("name");
CurrentBlock = new Block { Name = name };
} public void StartFooter(bool includeInDefault = true) {
CurrentBlock = footer;
footer.IncludeInDefault = includeInDefault;
} public void StartHeader(bool includeInDefault = true) {
CurrentBlock = header;
header.IncludeInDefault = includeInDefault;
} public void EndBlock() {
if (CurrentBlock == null)
return;
CurrentBlock.Length = template.Length - CurrentBlock.Start;
if (CurrentBlock != header && CurrentBlock != footer)
files.Add(CurrentBlock);
currentBlock = null;
} public virtual void Process(bool split, bool sync = true) {
if (split) {
EndBlock();
String headerText = template.ToString(header.Start, header.Length);
String footerText = template.ToString(footer.Start, footer.Length);
String outputPath = Path.GetDirectoryName(host.TemplateFile);
files.Reverse();
if (!footer.IncludeInDefault)
template.Remove(footer.Start, footer.Length);
foreach(Block block in files) {
String fileName = Path.Combine(outputPath, block.Name);
String content = headerText + template.ToString(block.Start, block.Length) + footerText;
generatedFileNames.Add(fileName);
CreateFile(fileName, content);
template.Remove(block.Start, block.Length);
}
if (!header.IncludeInDefault)
template.Remove(header.Start, header.Length);
}
} protected virtual void CreateFile(String fileName, String content) {
if (IsFileContentDifferent(fileName, content))
File.WriteAllText(fileName, content);
} public virtual String GetCustomToolNamespace(String fileName) {
return null;
} public virtual String DefaultProjectNamespace {
get { return null; }
} protected bool IsFileContentDifferent(String fileName, String newContent) {
return !(File.Exists(fileName) && File.ReadAllText(fileName) == newContent);
} private Manager(ITextTemplatingEngineHost host, StringBuilder template) {
this.host = host;
this.template = template;
} private Block CurrentBlock {
get { return currentBlock; }
set {
if (CurrentBlock != null)
EndBlock();
if (value != null)
value.Start = template.Length;
currentBlock = value;
}
} private class VSManager: Manager {
private readonly EnvDTE.ProjectItem templateProjectItem;
private readonly EnvDTE.DTE dte;
private readonly Action<String> checkOutAction;
private readonly Action<List<String>> projectSyncAction; public override String DefaultProjectNamespace {
get {
return templateProjectItem.ContainingProject.Properties.Item("DefaultNamespace").Value.ToString();
}
} public override String GetCustomToolNamespace(string fileName) {
return dte.Solution.FindProjectItem(fileName).Properties.Item("CustomToolNamespace").Value.ToString();
} public override void Process(bool split, bool sync) {
if (templateProjectItem.ProjectItems == null)
return;
base.Process(split, sync);
if (sync)
projectSyncAction.EndInvoke(projectSyncAction.BeginInvoke(generatedFileNames, null, null));
} protected override void CreateFile(String fileName, String content) {
if (IsFileContentDifferent(fileName, content)) {
CheckoutFileIfRequired(fileName);
File.WriteAllText(fileName, content);
}
} internal VSManager(ITextTemplatingEngineHost host, StringBuilder template)
: base(host, template) {
var hostServiceProvider = (IServiceProvider)host;
if (hostServiceProvider == null)
throw new ArgumentNullException("Could not obtain IServiceProvider");
dte = (EnvDTE.DTE) hostServiceProvider.GetService(typeof(EnvDTE.DTE));
if (dte == null)
throw new ArgumentNullException("Could not obtain DTE from host");
templateProjectItem = dte.Solution.FindProjectItem(host.TemplateFile);
checkOutAction = fileName => dte.SourceControl.CheckOutItem(fileName);
projectSyncAction = keepFileNames => ProjectSync(templateProjectItem, keepFileNames);
} private static void ProjectSync(EnvDTE.ProjectItem templateProjectItem, List<String> keepFileNames) {
var keepFileNameSet = new HashSet<String>(keepFileNames);
var projectFiles = new Dictionary<String, EnvDTE.ProjectItem>();
var originalFilePrefix = Path.GetFileNameWithoutExtension(templateProjectItem.FileNames[]) + ".";
foreach (EnvDTE.ProjectItem projectItem in templateProjectItem.ProjectItems)
projectFiles.Add(projectItem.FileNames[], projectItem); // Remove unused items from the project
foreach (var pair in projectFiles)
if (!keepFileNames.Contains(pair.Key) && !(Path.GetFileNameWithoutExtension(pair.Key) + ".").StartsWith(originalFilePrefix))
pair.Value.Delete(); // Add missing files to the project
foreach(String fileName in keepFileNameSet)
if (!projectFiles.ContainsKey(fileName))
templateProjectItem.ProjectItems.AddFromFile(fileName);
} private void CheckoutFileIfRequired(String fileName) {
var sc = dte.SourceControl;
if (sc != null && sc.IsItemUnderSCC(fileName) && !sc.IsItemCheckedOut(fileName))
checkOutAction.EndInvoke(checkOutAction.BeginInvoke(fileName, null, null));
}
}
} #>
新建一个类TestList,内容如下
public class TestList
{
public List<string> GetList()
{
return new List<string>() { "Name1","Name2","Name3"};
}
}
然后新建一个模板文件,model.tt,写入内容如下
<#@ template debug="false" hostspecific="true" language="C#" #>
<#@ assembly name="System.Core" #>
<#@ assembly name="$(TargetPath)" #>
<#@ import namespace="System.Linq" #>
<#@ import namespace="System.Text" #>
<#@ import namespace="System.Collections.Generic" #>
<#@ import namespace="TestAutoFac.Bll"#>
<#@include file="../MultipleOutputHelper.ttinclude"#> <# var manager = Manager.Create(Host, GenerationEnvironment);
TestList tl=new TestList();
List<string> lst=tl.GetList();foreach (var item in lst)
{
manager.StartNewFile(item+".cs");
//下面生成代码
#> using System;
public class <#=item#>
{
public <#=item#>()
{}
} <#
//上面生成代码
manager.EndBlock();
}
manager.Process(true);
#>
解释:<#@ assembly name="$(TargetPath)" #> 引入dll文件,这里用了vs的宏,指的是当前项目的dll
<#@include file="../MultipleOutputHelper.ttinclude"#> :引入根目录下的MultipleOutputHelper.ttinclude
<#@ import namespace="TestAutoFac.Bll"#>:引入TestList的命名空间
剩下的就没有说明了 ,看下项目的结构
红色划掉的是没用的

看下Name1.cs

大概就这样了 ,记录下 备忘
T4随记的更多相关文章
- 2017NOIP游记
记得去年这个时候,大概刚接触OI.没想到时间这么快,第一次2017NOIP之旅已经结束.初测成绩出来了,100+100+95+50=345,有浙江三十几名(@Cptraser 机房370大佬).总体感 ...
- THUWC2019 GG记
所以要什么时候才不会出现像这样的滚粗记呢? Day-?~Day-4 我也不清楚具体干了什么 不过学了很多东西,至少相对于去年还是个小菜鸡,今年已经变成大菜鸡了 Day-3~Day-1 几乎就是复习前面 ...
- NOIP2018凉凉记
首先声明一下,我去不了TG,因为我太菜了GD的某教授把我打到PJ了…… 虽然就我这实力普及都不一定1= 不管了,这次是普及,就当扎实基础了.反正HF的 $\text{hhz}$ 也考PJ,见个面多好啊 ...
- NOIP 2017 游(划水)记
Day 0 上午,大概做了一套(大)信(水)心题. 让我想想我题目都是些什么鬼.. T1:大水题.什么sort一下就过了.据说lemon上用map不会被卡常(lemon上评测,程序跑得蜜汁快). T2 ...
- NOIP2018 退役记
NOIP挂完,OI再见 AFO Day 0 早上的高铁,1点多到广州,2点多到酒店,下午就是颓颓颓,然后晚上随便刷了一下板子,反正PJ也没啥板子可以刷 就这样浪费了一天,我到底在干嘛 Day 1 早上 ...
- GDOI2018滚粗记
day-50: 高中全体成员去了北京训练,我被虐成傻逼(貌似总分全校倒数第2). day-20: 回广州了,间断式略微考好55555..... day0: 早上起床好像有点晚qwq 然后简单打了个FF ...
- NOIp2018 pj 滚粗记
NOIp2018 pj 滚粗记 考前 一个午觉睡完就到了考场 考中 \(T1\)水题切了 \(T2\)水题切了 \(T3\)好像是\(dp\),不会,先跳 \(T4\)像树上莫队一样,然后再欧拉序上面 ...
- noip2017普及 兔纸游玩记
初中的最后一场比赛...就这样结束了吧...QAQ时间...真够快的qwq 应该是初中的最后一篇游记了吧,尽量写多点... 这是一篇,初三 老年菜兔的 noip2017 普及游玩记吧! DAY 0 ...
- GDOI2017 五一游玩记
GDOI2017 到辣! 在五一比赛,成功躲了两天文化课. Day 0 早上睡到挺晚,想着同学在上课,我在睡觉,暗爽... 动车上,拿起电脑就是颓废,打模板!(然而真相是打了两个模板就开始颓了) 一天 ...
随机推荐
- ART、JIT、AOT、Dalvik之间有什么关系?
JIT与Dalvik JIT是"Just In Time Compiler"的缩写,就是"即时编译技术",与Dalvik虚拟机相关. 怎么理解这句话呢?这要从A ...
- cordova 生成发行版apk,并添加证书 – 畅玩Coding
原文:cordova 生成发行版apk,并添加证书 – 畅玩Coding 首先jdk生成证书. 1.进入jdk安装目录 D:\Java\jdk1.7.0\bin 2.执行命令 keytool -gen ...
- Docker + .NET Core(一)
原文:Docker + .NET Core(一) 前言: 环境:centos7.5 64 位 正文: 拉取 microsoft/dotnet, 安装完毕后执行 docker images 可以看到本地 ...
- 【b603】作业调度方案
Time Limit: 1 second Memory Limit: 50 MB [问题描述] 我们现在要利用m台机器加工n个工件,每个工件都有m道工序,每道工序都在不同的指定的机器上完成.每个工件的 ...
- 【codeforces 787C】Berzerk
[题目链接]:http://codeforces.com/contest/787/problem/C [题意] 给你怪物一开始所在的位置; 然后两人轮流操作; 可以选择让这个怪物前进自己的集合里面所拥 ...
- zookeeper 客户端操作
代码 /** * 创建zk客户端 * 实现循环监听的两个必要条件:1.程序不能结束2.递归调用监听器 * @author tele * */ public class Demo { ; //多个节点用 ...
- Risk Adaptive Information Flow Based Access Control
Systems and methods are provided to manage risk associated with access to information within a given ...
- GridLayout网格布局
网格布局特点: l 使容器中的各组件呈M行×N列的网格状分布. l 网格每列宽度相同,等于容器的宽度除以网格的列数. l 网格每行高度相同,等于容器的高度除以网格的行数. l 各组件的排列方式 ...
- apt-get install 的参数(add-apt-repository)
apt-get install 是 ubuntu 下的软件安装命令. sudo apt-get -y install: -y:yes,在命令行交互提示中,直接输入 yes: 1. 使用 add-apt ...
- 衡量镜头解像能力性能的指标-MTF曲线
MTF(Modulation Transfer Function,模量传递函数),是目前分析镜头解像能力的方法,可以用来评判镜头还原物体对比度的能力.说到MTF,不得不先提一下衡量镜头性能的两在重要指 ...