本文转自: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的更多相关文章

  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. 转 Multiple outputs from T4 made easy t4生成多文件

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

  3. [转] 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 ...

  4. t4-editor使用方法 Visual T4

    原文发布时间为:2011-05-17 -- 来源于本人的百度文章 [由搬家工具导入] http://visualstudiogallery.msdn.microsoft.com/40a887aa-f3 ...

  5. (转)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 ...

  6. Automake

    Automake是用来根据Makefile.am生成Makefile.in的工具 标准Makefile目标 'make all' Build programs, libraries, document ...

  7. C:\Program Files (x86)\Common Files\microsoft shared\TextTemplating\11.0

    Generating Files with the TextTransform Utility \Program Files\Common Files\Microsoft Shared\TextTem ...

  8. 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 ...

  9. filebeat.yml(中文配置详解)

    ################### Filebeat Configuration Example ######################### ####################### ...

随机推荐

  1. BestCoder11(Div2) 1003 Boring count (hdu 5056) 解题报告

    题目链接:http://acm.hdu.edu.cn/showproblem.php?pid=5056 题目意思:给出一条只有小写字母组成的序列S,问当中可以组成多少条每个字母出现的次数 <= ...

  2. js如何往数组Array中添加元素

    转载自:http://blog.sina.com.cn/s/blog_95fa28e60101mwup.html unshift:将参数添加到原数组开头,并返回数组的长度  pop:删除原数组最后一项 ...

  3. DOS 循环读取txt每一行内容

    在命令行窗口中输入: for /f %i in (f:\mydata.txt) do echo %i 如果要是写成批处理文件run.bat for /f %%i in (f:\mydata.txt) ...

  4. 解决 internet connection sharing 启动不了

    1.确认Windows Firewall服务是否启动(有异常可参考下面) a.打开注册表,找到HKEY_LOCAL_MACHINE\SYSTEM\CurrentControlSet\Services\ ...

  5. CSS备忘

    垂直居中:           先height再ling-height,都设成一样高 span 垂直居中:vertical-align:50%设置外边距:           margin-top,m ...

  6. C#学习笔记-----基于AppDomain的"插件式"开发

    很多时候,我们都想使用(开发)USB式(热插拔)的应用,例如,开发一个WinForm应用,并且这个WinForm应用能允许开发人员定制扩展插件,又例如,我们可能维护着一个WinService管理系统, ...

  7. Oracle 操作 - 配置

    http://blog.csdn.net/flyingbox/article/details/1823231 http://blog.csdn.net/libingquan008/article/de ...

  8. phpstorm 8 license key

    Learn Programming===== LICENSE BEGIN =====63758-1204201000000Ryqh0NCC73lpRm!XVcxFChJ2gTUR2lZtlLXrPLb ...

  9. js 实现文字列表滚动效果

    今天要实现抽奖名单在首页滚动展示的效果,就用js写了一个,代码如下: html代码: <style type="text/css"> *{margin:;padding ...

  10. Asp.net MVC 利用自定义RouteHandler来防止图片盗链

    你曾经注意过在你服务器请求日志中多了很多对图片资源的请求吗?这可能是有人在他们的网站中盗链了你的图片所致,这会占用你的服务器带宽.下面这种方法可以告诉你如何在ASP.NET MVC中实现一个自定义Ro ...