zoukankan      html  css  js  c++  java
  • [转]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;
    			}
    		}
    	}
    }#>

     

  • 相关阅读:
    [转] Vue + Webpack 组件式开发(练习环境)
    [转] 从零构建 vue2 + vue-router + vuex 开发环境到入门,实现基本的登录退出功能
    [转] Redux入门教程(快速上手)
    [转] 前端数据驱动的价值
    [转] React风格的企业前端技术
    [转] 对Array.prototype.slice.call()方法的理解
    [转] webpack之plugin内部运行机制
    [转] 静态资源的分布对网站加载速度的影响/浏览器对同一域名下并发加载资源数量
    Mysql 版本号、存储引擎、索引查询
    linux 查看CPU、内存、磁盘信息命令
  • 原文地址:https://www.cnblogs.com/freeliver54/p/3754570.html
Copyright © 2011-2022 走看看