原文:http://damieng.com/blog/2009/11/06/multiple-outputs-from-t4-made-easy-revisited

Usage

Initialization

You’ll need to get the code into your template – either copy the code in or reference it with an include directive. Then declare an instance of the Manager class passing in some environmental options such as the desired default output path. (For Visual Studio 2010 remove the #v3.5 portion from the language attribute)

<#@ template language="C#v3.5" hostspecific="True"
#><#@include file="Manager.ttinclude"
#><# var manager = Manager.Create(Host, GenerationEnvironment); #>

File blocks

Then add one line before and one line after each block which could be split out into it’s own file passing in what the filename would be if split. The EndBlock is optional if you want it to carry through to the next one :)

<# manager.StartNewFile("Employee.generated.cs"); #>
public class Employee { … }
<# manager.EndBlock(); #>

Headers & footers

Many templates need to share a common header/footer for such things as comments or using/import statements or turning on/off warnings. Simply use StartHeader and StartFooter and the blocks will be emitted to the start and end of all split files as well as being left in the original output file.

<# manager.StartHeader(); #>
// Code generated by a template
using System; <# manager.EndBlock(); #>

Process

At the end of the template call Process to handle splitting the files (true) or not (false). Anything not included in a specific StartNewFile block will remain in the original output file.

<# manager.Process(true); #>
<#@ assembly name="System.Core"
#><#@ assembly name="System.Data.Linq"
#><#@ assembly name="EnvDTE"
#><#@ assembly name="System.Xml"
#><#@ assembly name="System.Xml.Linq"
#><#@ import namespace="System"
#><#@ import namespace="System.CodeDom"
#><#@ import namespace="System.CodeDom.Compiler"
#><#@ import namespace="System.Collections.Generic"
#><#@ import namespace="System.Data.Linq"
#><#@ import namespace="System.Data.Linq.Mapping"
#><#@ import namespace="System.IO"
#><#@ import namespace="System.Linq"
#><#@ import namespace="System.Reflection"
#><#@ import namespace="System.Text"
#><#@ import namespace="System.Xml.Linq"
#><#@ import namespace="Microsoft.VisualStudio.TextTemplating"
#><#+ // Manager class records the various blocks so it can split them up
class Manager {
private class Block {
public String Name;
public int Start, Length;
} private Block currentBlock;
private List<Block> files = new List<Block>();
private Block footer = new Block();
private Block header = new Block();
private ITextTemplatingEngineHost host;
private StringBuilder template;
protected 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() {
CurrentBlock = footer;
} public void StartHeader() {
CurrentBlock = header;
} 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) {
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();
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);
}
}
} 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 EnvDTE.ProjectItem templateProjectItem;
private EnvDTE.DTE dte;
private Action<String> checkOutAction;
private Action<IEnumerable<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) {
if (templateProjectItem.ProjectItems == null)
return;
base.Process(split);
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 = (String fileName) => dte.SourceControl.CheckOutItem(fileName);
projectSyncAction = (IEnumerable<String> keepFileNames) => ProjectSync(templateProjectItem, keepFileNames);
} private static void ProjectSync(EnvDTE.ProjectItem templateProjectItem, IEnumerable<String> keepFileNames) {
var keepFileNameSet = new HashSet<String>(keepFileNames);
var projectFiles = new Dictionary<String, EnvDTE.ProjectItem>();
var originalFilePrefix = Path.GetFileNameWithoutExtension(templateProjectItem.get_FileNames()) + ".";
foreach(EnvDTE.ProjectItem projectItem in templateProjectItem.ProjectItems)
projectFiles.Add(projectItem.get_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));
}
}
} #>

转 Multiple outputs from T4 made easy t4生成多文件的更多相关文章

  1. Multiple outputs from T4 made easy – revisited » DamienG

    Multiple outputs from T4 made easy – revisited » DamienG Multiple outputs from T4 made easy – revisi ...

  2. [转] How to generate multiple outputs from single T4 template (T4 输出多个文件)

    本文转自:http://www.olegsych.com/2008/03/how-to-generate-multiple-outputs-from-single-t4-template/ Updat ...

  3. FluentData-新型轻量级ORM 利用T4模板 批量生成多文件 实体和业务逻辑 代码

    FluentData,它是一个轻量级框架,关注性能和易用性. 下载地址:FlunenData.Model 利用T4模板,[MultipleOutputHelper.ttinclude]批量生成多文件 ...

  4. T4模板根据DB生成实体类

    1.前言 为什么会有这篇文章了,最近看到了一些框架,里面要写的代码太多了,故此就想偷懒,要是能写出一个T4模板,在数据库添加表后,根据模板就可以自动生成了类文件了,这样多好,心动不如行动.记得使用T4 ...

  5. T4教程1 T4模版引擎之基础入门

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

  6. T4教程2 T4模版引擎之生成数据库实体类

    T4模版引擎之生成数据库实体类   在通过T4模版引擎之基础入门 对T4有了初步印象后,我们开始实战篇.T4模板引擎可以当做一个代码生成器,代码生成器的职责当然是用来生成代码(这不是废话吗).而这其中 ...

  7. 使用T4为数据库自动生成实体类

    T4 (Text Template Transformation Toolkit) 是一个基于模板的代码生成器.使用T4你可以通过写一些ASP.NET-like模板,来生成C#, T-SQL, XML ...

  8. c# 利用t4模板,自动生成Model类

    我们在用ORM(比如dapper)的时候,很多时候都需要自己写Model层(当然也有很多orm框架自带了这种功能,比如ef),特别是表里字段比较多的时候,一个Model要写半天,而且Model如果用于 ...

  9. T4生成多文件时,不生成自己

    如:我用的网上的生成多文件的一个include文件. 生成多文件时,默认会生成一个以自己名字命名的文件如: 有一个demo.tt文件,生成时会出来一个demo.cs文件(默认情况下) 解决方法: Fo ...

随机推荐

  1. ExceptionLess的webAPI调用

    引用 <package id="bootstrap" version="3.0.0" targetFramework="net461" ...

  2. [转] 合理使用npm version与npm dist-tag详解

    第一步:发布第一个稳定版本 npm publish//1.0.0 第二步:修改文件继续发布第二个版本 git add -A && git commit -m "c" ...

  3. C# 之 判断一个字符是否是汉字

    判断一个字符是不是汉字通常有三种方法: [1] 用 ASCII 码判断:[2] 用汉字的 UNICODE 编码范围判断:[3] 用正则表达式判断. 1.用ASCII码判断 在 ASCII码表中,英文的 ...

  4. JMeter执行压测输出HTML图形化报表(二)

    命令行模式将jtl转成测试图表 注意此方法只使用jmeter3.0以后版本 第一种:在测试过程中将jtl转成测试报告(在jmeter的bin目录下执行) jmeter -n -t baidu_requ ...

  5. ELK使用1-Elasticsearch使用

    一.es 1.通过curl命令获取es进群信息 a.curl -i(设置协议的头信息) -XGET 'http:192.168.30.41:9200/_count' b.查看集群状态 curl -XG ...

  6. Selenium自动化测试框架的搭建

          说 起自动化测试,我想大家都会有个疑问,要不要做自动化测试? 自动化测试给我们带来的收益是否会超出在建设时所投入的成本,这个嘛别说是我,即便是高手也很难回答,自动化测试的初衷是美好的,而测 ...

  7. BZOJ2287 【POJ Challenge】消失之物 动态规划 分治

    原文链接http://www.cnblogs.com/zhouzhendong/p/8684027.html 题目传送门 - BZOJ2287 题意 有$n$个物品,第$i$个物品的体积为$w_i$. ...

  8. 谁说java里面有返回值的方法必须要有返回值,不然会报错????

    慢慢的总是发现以前的学得时候有些老师讲的不对的地方! 所以还是尽量别把一些东西说的那么绝对,不然总是很容易误导别人,特别是一些你自己根本就没有试过的东西,然后又斩钉截铁的告诉别人,这样不行,肯定不行什 ...

  9. js让元素获取焦点

    js让元素获取焦点$("#startAddress").focus();

  10. 01. Numpy模块

    1.科学计算工具-Numpy基础数据结构 1.1.数组ndarray的属性 NumPy数组是一个多维数组对象,称为ndarray.其由两部分组成:① 实际的数据② 描述这些数据的元数据 注意数组格式, ...