Generate multiple files with T4 (reproduced)

Generate multiple files with T4 (reproduced)

Transfer from: http://blog.csdn.net/cracklibby/article/details/51319799

When I first recognized and tried to use T4 to generate code, there seemed to be relatively few relevant learning materials. But now there are related chapters in MSDN of VS2010, you can refer to the chapter of "Code Generation and Text Templates". You can write templates in C # syntax, which is a lot more comfortable.

It soon became apparent that T4 had difficulty generating multiple files, and Microsoft did not seem to rush to improve this. Through the search, I found an article " Generating multiple files with T4 " from InfoQ , linking to an article, Damien Guard extension can easily generate multiple files. The original text is in English, which can be understood, but if it is translated, it is too hard to consider the words.

First, save the following code as a template file (for example, save the file as Manager.ttinclude):

<#@ assembly name="System.Core"#>  
<#@ assembly name="System.Data.Linq"#>  
<#@ assembly name="EnvDTE"#>  
<#@ assembly name="System.Xml"#>  
<#@ assembly name="System.Xml.Linq"#>  
<#@ import namespace="System"#>  
<#@ import namespace="System.CodeDom"#>  
<#@ import namespace="System.CodeDom.Compiler"#>  
<#@ import namespace="System.Collections.Generic"#>  
<#@ import namespace="System.Data.Linq"#>  
<#@ import namespace="System.Data.Linq.Mapping"#>  
<#@ import namespace="System.IO"#>  
<#@ import namespace="System.Linq"#>  
<#@ import namespace="System.Reflection"#>  
<#@ import namespace="System.Text"#>  
<#@ import namespace="System.Xml.Linq"#>  
<#@ import namespace="Microsoft.VisualStudio.TextTemplating"#>  
<#+  
   
// Manager class records the various blocks so it can split them up  
class Manager {  
    private class Block {  
        public String Name;  
        public int Start, Length;  
    }  
   
    private Block currentBlock;  
    private List<Block> files = new List<Block>();  
    private Block footer = new Block();  
    private Block header = new Block();  
    private ITextTemplatingEngineHost host;  
    private StringBuilder template;  
    protected List<String> generatedFileNames = new List<String>();  
   
    public static Manager Create(ITextTemplatingEngineHost host, StringBuilder template) {  
        return (host is IServiceProvider) ? new VSManager(host, template) : new Manager(host, template);  
    }  
   
    public void StartNewFile(String name) {  
        if (name == null)  
            throw new ArgumentNullException("name");  
        CurrentBlock = new Block { Name = name };  
    }  
   
    public void StartFooter() {  
        CurrentBlock = footer;  
    }  
   
    public void StartHeader() {  
        CurrentBlock = header;  
    }  
   
    public void EndBlock() {  
        if (CurrentBlock == null)  
            return;  
        CurrentBlock.Length = template.Length - CurrentBlock.Start;  
        if (CurrentBlock != header && CurrentBlock != footer)  
            files.Add(CurrentBlock);  
        currentBlock = null;  
    }  
   
    public virtual void Process(bool split) {  
        if (split) {  
            EndBlock();  
            String headerText = template.ToString(header.Start, header.Length);  
            String footerText = template.ToString(footer.Start, footer.Length);  
            String outputPath = Path.GetDirectoryName(host.TemplateFile);  
            files.Reverse();  
            foreach(Block block in files) {  
                String fileName = Path.Combine(outputPath, block.Name);  
                String content = headerText + template.ToString(block.Start, block.Length) + footerText;  
                generatedFileNames.Add(fileName);  
                CreateFile(fileName, content);  
                template.Remove(block.Start, block.Length);  
            }  
        }  
    }  
   
    protected virtual void CreateFile(String fileName, String content) {  
        if (IsFileContentDifferent(fileName, content))  
            File.WriteAllText(fileName, content);  
    }  
   
    public virtual String GetCustomToolNamespace(String fileName) {  
        return null;  
    }  
   
    public virtual String DefaultProjectNamespace {  
        get { return null; }  
    }  
   
    protected bool IsFileContentDifferent(String fileName, String newContent) {  
        return !(File.Exists(fileName) && File.ReadAllText(fileName) == newContent);  
    }  
   
    private Manager(ITextTemplatingEngineHost host, StringBuilder template) {  
        this.host = host;  
        this.template = template;  
    }  
   
    private Block CurrentBlock {  
        get { return currentBlock; }  
        set {  
            if (CurrentBlock != null)  
                EndBlock();  
            if (value != null)  
                value.Start = template.Length;  
            currentBlock = value;  
        }  
    }  
   
    private class VSManager: Manager {  
        private EnvDTE.ProjectItem templateProjectItem;  
        private EnvDTE.DTE dte;  
        private Action<String> checkOutAction;  
        private Action<IEnumerable<String>> projectSyncAction;  
   
        public override String DefaultProjectNamespace {  
            get {  
                return templateProjectItem.ContainingProject.Properties.Item("DefaultNamespace").Value.ToString();  
            }  
        }  
   
        public override String GetCustomToolNamespace(string fileName) {  
            return dte.Solution.FindProjectItem(fileName).Properties.Item("CustomToolNamespace").Value.ToString();  
        }  
   
        public override void Process(bool split) {  
            if (templateProjectItem.ProjectItems == null)  
                return;  
            base.Process(split);  
            projectSyncAction.EndInvoke(projectSyncAction.BeginInvoke(generatedFileNames, null, null));  
        }  
   
        protected override void CreateFile(String fileName, String content) {  
            if (IsFileContentDifferent(fileName, content)) {  
                CheckoutFileIfRequired(fileName);  
                File.WriteAllText(fileName, content);  
            }  
        }  
   
        internal VSManager(ITextTemplatingEngineHost host, StringBuilder template)  
            : base(host, template) {  
            var hostServiceProvider = (IServiceProvider) host;  
            if (hostServiceProvider == null)  
                throw new ArgumentNullException("Could not obtain IServiceProvider");  
            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);  
            checkOutAction = (String fileName) => dte.SourceControl.CheckOutItem(fileName);  
            projectSyncAction = (IEnumerable<String> keepFileNames) => ProjectSync(templateProjectItem, keepFileNames);  
        }  
   
        private static void ProjectSync(EnvDTE.ProjectItem templateProjectItem, IEnumerable<String> keepFileNames) {  
            var keepFileNameSet = new HashSet<String>(keepFileNames);  
            var projectFiles = new Dictionary<String, EnvDTE.ProjectItem>();  
            var originalFilePrefix = Path.GetFileNameWithoutExtension(templateProjectItem.get_FileNames(0)) + ".";  
            foreach(EnvDTE.ProjectItem projectItem in templateProjectItem.ProjectItems)  
                projectFiles.Add(projectItem.get_FileNames(0), projectItem);  
   
            // Remove unused items from the project  
            foreach(var pair in projectFiles)  
                if (!keepFileNames.Contains(pair.Key) && !(Path.GetFileNameWithoutExtension(pair.Key) + ".").StartsWith(originalFilePrefix))  
                    pair.Value.Delete();  
   
            // Add missing files to the project  
            foreach(String fileName in keepFileNameSet)  
                if (!projectFiles.ContainsKey(fileName))  
                    templateProjectItem.ProjectItems.AddFromFile(fileName);  
        }  
   
        private void CheckoutFileIfRequired(String fileName) {  
            var sc = dte.SourceControl;  
            if (sc != null && sc.IsItemUnderSCC(fileName) && !sc.IsItemCheckedOut(fileName))  
                checkOutAction.EndInvoke(checkOutAction.BeginInvoke(fileName, null, null));  
        }  
    }  
} #>  

 

Next, reference this template in the T4 template file and declare an instance of the Manager class:

<#@ template language="C#" hostspecific="True"#>  
<#@include file="Manager.ttinclude"#>  
<# var manager = Manager.Create(Host, GenerationEnvironment); #>  

 

Using two lines of code can make the code output to a separate file. The code you want to output can be written in the middle of these two statements. The parameter of StartNewFile is the name of the output file:

<# manager.StartNewFile("Employee.generated.cs"); #>  
  
<# manager.EndBlock(); #>  

 

For example, you can write:

<# manager.StartNewFile("Employee.generated.cs"); #>  
public class Employee {  }  
<# manager.EndBlock(); #>  

 

You can also output the same header or top for each output file, just need the corresponding statement:

<# manager.StartHeader (); #>  
// Code generated by a template  
using System;  
<# manager.EndBlock(); #>  
   
<# manager.StartFooter(); #>  
// It's the end  
<# manager.EndBlock(); #>  

 

Finally use this sentence to perform the output of multiple files:

<# manager.Process(true); #>  

 

Published 17 original articles · Like 230 · Visits 340,000+

Guess you like

Origin blog.csdn.net/cxu123321/article/details/105514714