[转]Multiple outputs from T4 made easy
本文转自:http://damieng.com/blog/2009/01/22/multiple-outputs-from-t4-made-easy
One of the things I wanted my LINQ to SQL T4 templates to do was be able to split the output into a file-per-entity. Existing solutions used either a separate set of templates with duplicate code or intrusive handling code throughout the template. Here’s my helper class to abstract the problem away from what is already complicated enough template code.
Using the Manager class
Setup
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.
<#@ template language="C#v3.5" hostspecific="True"
#><#@ include file="Manager.ttinclude"
#><# var manager = new Manager(Host, GenerationEnvironment, true) { OutputPath = Path.GetDirectoryName(Host.TemplateFile) }; #>
Define a block
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.
<# manager.StartBlock("Employee.generated.cs"); #>
public class Employee { … }
<# manager.EndBlock(); #>
Headers and 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/EndHeader and StartFooter/EndFooter. The resulting blocks will be emitted into all split files and left in the original output too.
<# manager.StartHeader(); #>
// Code generated template
using System;
<# manager.EndHeader(); #>
Process
At the end of the template call Process to handle splitting the files (true) or not (false). Anything not included in a specific start/end block will remain in the original output file.
<# manager.Process(true); #>
When processing each block name in the Output path will either be overwritten or deleted to enable proper clean-up. It will also add and remove the files from Visual Studio somake sure your generated names aren’t going to collide with hand-written ones!
Manager classes
Here is the Manger class itself as well as the small ManagementStrategy classes that determines what to do with the files within Visual Studio (add/remove project items) and outside of Visual Studio (create/delete files).
Download Manager.ttinclude (4KB)
<#@ assembly name="System.Core"
#><#@ assembly name="EnvDTE"
#><#@ import namespace="System.Collections.Generic"
#><#@ import namespace="System.IO"
#><#@ import namespace="System.Text"
#><#@ import namespace="Microsoft.VisualStudio.TextTemplating"
#><#+
// T4 Template Block manager for handling multiple file outputs more easily.
// Copyright (c) Microsoft Corporation. All rights reserved.
// This source code is made available under the terms of the Microsoft Public License (MS-PL)
// Manager class records the various blocks so it can split them up
class Manager
{
private struct Block {
public String Name;
public int Start, Length;
}
private List<Block> blocks = new List<Block>();
private Block currentBlock;
private Block footerBlock = new Block();
private Block headerBlock = new Block();
private ITextTemplatingEngineHost host;
private ManagementStrategy strategy;
private StringBuilder template;
public String OutputPath { get; set; }
public Manager(ITextTemplatingEngineHost host, StringBuilder template, bool commonHeader) {
this.host = host;
this.template = template;
OutputPath = String.Empty;
strategy = ManagementStrategy.Create(host);
}
public void StartBlock(String name) {
currentBlock = new Block { Name = name, Start = template.Length };
}
public void StartFooter() {
footerBlock.Start = template.Length;
}
public void EndFooter() {
footerBlock.Length = template.Length - footerBlock.Start;
}
public void StartHeader() {
headerBlock.Start = template.Length;
}
public void EndHeader() {
headerBlock.Length = template.Length - headerBlock.Start;
}
public void EndBlock() {
currentBlock.Length = template.Length - currentBlock.Start;
blocks.Add(currentBlock);
}
public void Process(bool split) {
String header = template.ToString(headerBlock.Start, headerBlock.Length);
String footer = template.ToString(footerBlock.Start, footerBlock.Length);
blocks.Reverse();
foreach(Block block in blocks) {
String fileName = Path.Combine(OutputPath, block.Name);
if (split) {
String content = header + template.ToString(block.Start, block.Length) + footer;
strategy.CreateFile(fileName, content);
template.Remove(block.Start, block.Length);
} else {
strategy.DeleteFile(fileName);
}
}
}
}
class ManagementStrategy
{
internal static ManagementStrategy Create(ITextTemplatingEngineHost host) {
return (host is IServiceProvider) ? new VSManagementStrategy(host) : new ManagementStrategy(host);
}
internal ManagementStrategy(ITextTemplatingEngineHost host) { }
internal virtual void CreateFile(String fileName, String content) {
File.WriteAllText(fileName, content);
}
internal virtual void DeleteFile(String fileName) {
if (File.Exists(fileName))
File.Delete(fileName);
}
}
class VSManagementStrategy : ManagementStrategy
{
private EnvDTE.ProjectItem templateProjectItem;
internal VSManagementStrategy(ITextTemplatingEngineHost host) : base(host) {
IServiceProvider hostServiceProvider = (IServiceProvider)host;
if (hostServiceProvider == null)
throw new ArgumentNullException("Could not obtain hostServiceProvider");
EnvDTE.DTE 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);
}
internal override void CreateFile(String fileName, String content) {
base.CreateFile(fileName, content);
((EventHandler)delegate { templateProjectItem.ProjectItems.AddFromFile(fileName); }).BeginInvoke(null, null, null, null);
}
internal override void DeleteFile(String fileName) {
((EventHandler)delegate { FindAndDeleteFile(fileName); }).BeginInvoke(null, null, null, null);
}
private void FindAndDeleteFile(String fileName) {
foreach(EnvDTE.ProjectItem projectItem in templateProjectItem.ProjectItems) {
if (projectItem.get_FileNames(0) == fileName) {
projectItem.Delete();
return;
}
}
}
}#>
[转]Multiple outputs from T4 made easy的更多相关文章
- Multiple outputs from T4 made easy – revisited » DamienG
Multiple outputs from T4 made easy – revisited » DamienG Multiple outputs from T4 made easy – revisi ...
- 转 Multiple outputs from T4 made easy t4生成多文件
原文:http://damieng.com/blog/2009/11/06/multiple-outputs-from-t4-made-easy-revisited Usage Initializat ...
- [转] 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 ...
- t4-editor使用方法 Visual T4
原文发布时间为:2011-05-17 -- 来源于本人的百度文章 [由搬家工具导入] http://visualstudiogallery.msdn.microsoft.com/40a887aa-f3 ...
- (转)Let’s make a DQN 系列
Let's make a DQN 系列 Let's make a DQN: Theory September 27, 2016DQN This article is part of series Le ...
- Automake
Automake是用来根据Makefile.am生成Makefile.in的工具 标准Makefile目标 'make all' Build programs, libraries, document ...
- C:\Program Files (x86)\Common Files\microsoft shared\TextTemplating\11.0
Generating Files with the TextTransform Utility \Program Files\Common Files\Microsoft Shared\TextTem ...
- LEK-Introduction-Installation-Usage-new
LEK is a set of tools which can take data from any source and search, analyze, and visualize it in r ...
- filebeat.yml(中文配置详解)
################### Filebeat Configuration Example ######################### ####################### ...
随机推荐
- XP下使用IIS访问asp出现无权查看网页问题的解决办法
这是用户权限问题,因为你用的磁盘是NTFS格式. 解决方法: 一.添加用户(“Everyone”或者“IUSR_你的机器名”,如IUSR_HONG,即“Internet 来宾用户”) 二.修改用户权限 ...
- QQ图片名字
ﻩ并亲了你一下ﻩ大兔子҉҉大兔子҉҉҉҉҉҉҉҉
- 改数(洛谷 U5398)
题目背景 又是一年NOIP,科学馆的五楼:"我们看下这道题,我们来模拟一下-2,3,5,7,12-这其实就是一个a[i+1]-a[i]=i的序列--"那熟悉的凌波教鞭,熟悉的憨厚的 ...
- Java内部类的访问规则
1.内部类可以直接访问外部类中的成员,包括私有 原因:因为在内部类中持有一个外部类的应用,格式:外部类.this class Outer { private int x = 1; c ...
- iOS通过ASIHTTPRequest提交JSON数据
先验知识——什么是ASIHTTPRequest? 使用iOS SDK中的HTTP网络请求API,相当的复杂,调用很繁琐,ASIHTTPRequest就是一个对CFNetwork API进行了封装,并且 ...
- ytu 2002:C语言实验——单词统计(水题)
C语言实验——单词统计 Time Limit: 1 Sec Memory Limit: 64 MBSubmit: 61 Solved: 34[Submit][Status][Web Board] ...
- [译] Web API 之 简介
事实上,MVC 框架本身已经提供了构建REST风格服务的基础,而Web API 只是让你可以更加容易和快捷的构建REST服务. 特性 基于约定的 CRUD Actions: 自动按照HTTP的acto ...
- List Copy
//要复制的实例必须可序列化,包括实例引用的其它实例都必须在类定义时加[Serializable]特性. public static T Copy<T>(T RealObject) { u ...
- iOS经典面试题
前言 写这篇文章的目的是因为前两天同学想应聘iOS开发,从网上找了iOS面试题和答案让我帮忙看看.我扫了一眼,倒吸了一口冷气,仔细一看,气的发抖.整篇题目30多个没有一个答案是对的,总结这篇面试题的作 ...
- loj 1407(2-sat + 枚举 + 输出一组可行解 )
题目链接:http://acm.hust.edu.cn/vjudge/problem/viewProblem.action?id=27115 思路:有一个trick要注意:当情况为 2 x y 时,可 ...