[转]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 ######################### ####################### ...
随机推荐
- Java for LeetCode 174 Dungeon Game
The demons had captured the princess (P) and imprisoned her in the bottom-right corner of a dungeon. ...
- Cocos2d-JS坐标系统
标准屏幕坐标系 如果接触过iOS,Android,Windows Phone等系统的应用开发,或使用DOM,CSS开发过Web网页,开发者会非常熟悉所谓的标准屏幕坐标系:左上角为原点,向右为X轴正方向 ...
- 搭建Maven工程的时候,做单元测试,报ClassNotFoundException
搭建Maven工程的时候报错 问题原因是在spring.xml中配置的 classpath:config.properties 没有在工程中创建.
- [Android Pro] 关于Android的HTTP客户端的小秘密
原文:http://android-developers.blogspot.com/2011/09/androids-http-clients.html 译文:http://yunfeng.sinaa ...
- 《JavaScript高级程序设计》学习笔记
系统学习JS, 从<JavaScript高级程序设计>入门,通过学习jQuery或者angularJS源码来进阶. 第1章 JavaScript简介 1.JS问世的目的是处理以前由服务器端 ...
- Java查询网址
Java在线帮助文档: http://docs.oracle.com/javase/8/docs/technotes/guides/desc_jdk_structure.html Java小知识讲解: ...
- 记32位Oracle客户端登录报12560协议适配器错误的解决办法
国庆买了一台新电脑ThinkPad E431,i5双核CPU,8G内存,硬盘比较坑爹5400转的500G,重点是预装win8的64位简体中文版.大学时买了第一台电脑神舟笔记本,因为神舟电脑便宜,所以没 ...
- DbHelper-SQL数据库访问助手
using System; using System.Data; using System.Data.SqlClient; namespace Whir.Software.Framework.Ulti ...
- Gym 100971D Laying Cables 单调栈
Description One-dimensional country has n cities, the i-th of which is located at the point xi and h ...
- ECJTU大一暑假集训
第二场比赛:一签到题没做出来!!!死活不远做下去了,开始发狂,最后还有2个半小时开始做别的,陆续A了几道: 我还能怪谁呢,我渣,我傻逼,就这样!! 7/19:早就想自己建一个博客了,也就是一直想想没 ...