本文转自: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.

  1. <#@ template language="C#v3.5" hostspecific="True"
  2. #><#@ include file="Manager.ttinclude"
  3. #><# 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.

  1. <# manager.StartBlock("Employee.generated.cs"); #>
  2. public class Employee { … }
  3. <# 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.

  1. <# manager.StartHeader(); #>
  2. // Code generated template
  3. using System;
  4. <# 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.

  1. <# 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)

  1. <#@ assembly name="System.Core"
  2. #><#@ assembly name="EnvDTE"
  3. #><#@ import namespace="System.Collections.Generic"
  4. #><#@ import namespace="System.IO"
  5. #><#@ import namespace="System.Text"
  6. #><#@ import namespace="Microsoft.VisualStudio.TextTemplating"
  7. #><#+
  8. // T4 Template Block manager for handling multiple file outputs more easily.
  9. // Copyright (c) Microsoft Corporation. All rights reserved.
  10. // This source code is made available under the terms of the Microsoft Public License (MS-PL)
  11. // Manager class records the various blocks so it can split them up
  12. class Manager
  13. {
  14. private struct Block {
  15. public String Name;
  16. public int Start, Length;
  17. }
  18. private List<Block> blocks = new List<Block>();
  19. private Block currentBlock;
  20. private Block footerBlock = new Block();
  21. private Block headerBlock = new Block();
  22. private ITextTemplatingEngineHost host;
  23. private ManagementStrategy strategy;
  24. private StringBuilder template;
  25. public String OutputPath { get; set; }
  26. public Manager(ITextTemplatingEngineHost host, StringBuilder template, bool commonHeader) {
  27. this.host = host;
  28. this.template = template;
  29. OutputPath = String.Empty;
  30. strategy = ManagementStrategy.Create(host);
  31. }
  32. public void StartBlock(String name) {
  33. currentBlock = new Block { Name = name, Start = template.Length };
  34. }
  35. public void StartFooter() {
  36. footerBlock.Start = template.Length;
  37. }
  38. public void EndFooter() {
  39. footerBlock.Length = template.Length - footerBlock.Start;
  40. }
  41. public void StartHeader() {
  42. headerBlock.Start = template.Length;
  43. }
  44. public void EndHeader() {
  45. headerBlock.Length = template.Length - headerBlock.Start;
  46. }
  47. public void EndBlock() {
  48. currentBlock.Length = template.Length - currentBlock.Start;
  49. blocks.Add(currentBlock);
  50. }
  51. public void Process(bool split) {
  52. String header = template.ToString(headerBlock.Start, headerBlock.Length);
  53. String footer = template.ToString(footerBlock.Start, footerBlock.Length);
  54. blocks.Reverse();
  55. foreach(Block block in blocks) {
  56. String fileName = Path.Combine(OutputPath, block.Name);
  57. if (split) {
  58. String content = header + template.ToString(block.Start, block.Length) + footer;
  59. strategy.CreateFile(fileName, content);
  60. template.Remove(block.Start, block.Length);
  61. } else {
  62. strategy.DeleteFile(fileName);
  63. }
  64. }
  65. }
  66. }
  67. class ManagementStrategy
  68. {
  69. internal static ManagementStrategy Create(ITextTemplatingEngineHost host) {
  70. return (host is IServiceProvider) ? new VSManagementStrategy(host) : new ManagementStrategy(host);
  71. }
  72. internal ManagementStrategy(ITextTemplatingEngineHost host) { }
  73. internal virtual void CreateFile(String fileName, String content) {
  74. File.WriteAllText(fileName, content);
  75. }
  76. internal virtual void DeleteFile(String fileName) {
  77. if (File.Exists(fileName))
  78. File.Delete(fileName);
  79. }
  80. }
  81. class VSManagementStrategy : ManagementStrategy
  82. {
  83. private EnvDTE.ProjectItem templateProjectItem;
  84. internal VSManagementStrategy(ITextTemplatingEngineHost host) : base(host) {
  85. IServiceProvider hostServiceProvider = (IServiceProvider)host;
  86. if (hostServiceProvider == null)
  87. throw new ArgumentNullException("Could not obtain hostServiceProvider");
  88. EnvDTE.DTE dte = (EnvDTE.DTE)hostServiceProvider.GetService(typeof(EnvDTE.DTE));
  89. if (dte == null)
  90. throw new ArgumentNullException("Could not obtain DTE from host");
  91. templateProjectItem = dte.Solution.FindProjectItem(host.TemplateFile);
  92. }
  93. internal override void CreateFile(String fileName, String content) {
  94. base.CreateFile(fileName, content);
  95. ((EventHandler)delegate { templateProjectItem.ProjectItems.AddFromFile(fileName); }).BeginInvoke(null, null, null, null);
  96. }
  97. internal override void DeleteFile(String fileName) {
  98. ((EventHandler)delegate { FindAndDeleteFile(fileName); }).BeginInvoke(null, null, null, null);
  99. }
  100. private void FindAndDeleteFile(String fileName) {
  101. foreach(EnvDTE.ProjectItem projectItem in templateProjectItem.ProjectItems) {
  102. if (projectItem.get_FileNames(0) == fileName) {
  103. projectItem.Delete();
  104. return;
  105. }
  106. }
  107. }
  108. }#>

[转]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. win激活查询及修改

    slmgr.vbs -dlv 命令可以查询到Win8.1的激活信息,包括:激活ID.安装ID.激活截止日期!   slmgr.vbs -dli 命令可以查询到操作系统版本.部分产品密钥.许可证状态! ...

  2. ShareSDK集成微信、QQ、微博分享

    1.前言 为什么要使用第三方的作为集成分享的工具呢?而不去用官方的呢?有什么区别么? 一个字"快",如果你使用官方的得一个个集成他们的SDK,相信这是一个痛苦的过程. 2.准备需要 ...

  3. Android之网络编程

    本文主要包括三方面内容 Httpurlconnection中doGet与doPost方法实现提交数据到服务器 HttpClient中doGet与doPost方法实现提交数据到服务器 android-a ...

  4. Hadoop 1.1.2 eclipse plugin 编译 win7 集成

    Windows平台上使用ANT编译Hadoop Eclipse Plugin 一.准备工作:   1.安装JDK 下载页面:http://www.oracle.com/technetwork/java ...

  5. 【ASP.NET MVC】个人复习整理

    1.为 Action 标注 Attribute 限制访问 public class HomeController : Controller { [HttpPost] public ActionResu ...

  6. mysql忘记密码修改方法

    1.干掉mysqld进程 kill -TERM mysqld 2.使用下面命令启动mysqld /usr/bin/mysqld_safe --skip-grant-tables & 3.新开一 ...

  7. C# WebProxy POST 或者 GET

    代理服务器无账号和密码的代理服务器: //创建请求 HttpWebRequest request = (HttpWebRequest)WebRequest.Create(url); //实例化一个We ...

  8. poj 1087 最大流

    没啥好说的,慢慢建图 Sample Input 4 A B C D 5 laptop B phone C pager B clock B comb X 3 B X X A X D Sample Out ...

  9. android模拟器使用PC串口调试

    android模拟器使用PC串口调试1.模拟器可以使用PC的串口  启动模拟器并加载PC串口 命令如下:  运行 emulator @模拟器名称 -qemu -serial COM12.查看串口是否被 ...

  10. UVALive 6887 Book Club 最大流解最大匹配

    题目连接: https://icpcarchive.ecs.baylor.edu/index.php?option=com_onlinejudge&Itemid=8&page=show ...