Создать несколько файлов с T4 (воспроизведено)

Создать несколько файлов с T4 (воспроизведено)

Перевод с: http://blog.csdn.net/cracklibby/article/details/51319799

Когда я впервые узнал и попытался использовать T4 для генерации кода, казалось, было относительно немного соответствующих учебных материалов. Но теперь в MSDN VS2010 есть соответствующие главы, вы можете обратиться к главе «Генерация кода и текстовые шаблоны». Вы можете писать шаблоны в синтаксисе C #, что намного удобнее.

Вскоре стало очевидно, что у T4 возникли трудности с созданием нескольких файлов, и Microsoft, похоже, не спешила улучшать это. Благодаря поиску я обнаружил статью « Создание нескольких файлов с помощью T4 » из InfoQ , ссылающуюся на статью, расширение Damien Guard может легко создавать несколько файлов. Оригинальный текст на английском языке, который можно понять, но если он переведен, слишком сложно рассмотреть слова.

Сначала сохраните следующий код в качестве файла шаблона (например, сохраните файл как 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 записывает различные блоки, чтобы разделить их на   
класс Manager {   
    частный класс Block {   
        public String Name;  
        public int Start, Length;  
    }   
   
    закрытый блок currentBlock;  
    приватный список <Block> files = new List <Block> ();  
    закрытый нижний колонтитул блока = новый блок ();  
    заголовок частного блока = новый блок ();  
    частный хост ITextTemplatingEngineHost;  
    закрытый шаблон StringBuilder;  
    защищенный список <String> generateFileNames = новый список <String> ();  
   
    public static Manager Create (хост ITextTemplatingEngineHost, шаблон StringBuilder) {   
        return (хост - это IServiceProvider)? новый VSManager (хост, шаблон): новый менеджер (хост, шаблон);  
    }   
   
    public void StartNewFile (String name) {   
        if (name == null)   
            throw new ArgumentNullException ("name");  
        CurrentBlock = новый блок {имя = имя};  
    }   
   
    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! = заголовок && CurrentBlock! = нижний колонтитул)   
            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 (Блок блок в файлах) {  
                String fileName = Path.Combine (outputPath, block.Name);  
                String content = headerText + template.ToString (block.Start, block.Length) + footerText;  
                generatedFileNames.Add (имя_файла);  
                CreateFile (fileName, content);  
                template.Remove (block.Start, block.Length);  
            }   
        }   
    }   
   
    защищенный виртуальный void CreateFile (String fileName, String content) {   
        if (IsFileContentDifferent (fileName, content))   
            File.WriteAllText (fileName, content);  
    }   
   
    публичная виртуальная строка GetCustomToolNamespace (String fileName) {   
    публичная виртуальная строка DefaultProjectNamespace {   
        get {return null; }   
        return null;  
    }  
            currentBlock = значение;  
   
    }   
   
    protected bool IsFileContentDifferent (String fileName, String newContent) {   
        return! (File.Exists (fileName) && File.ReadAllText (fileName) == newContent);  
    }   
   
    приватный менеджер (хост ITextTemplatingEngineHost, шаблон 
        StringBuilder ) {   this.host = host;  
        this.template = template;  
    }   
   
    закрытый блок CurrentBlock {   
        get {return currentBlock; }   
        set {   
            if (CurrentBlock! = null)   
                EndBlock ();  
            if (value! = null)   
                value.Start = template.Length;   
    }  
        }   
            return dte.Solution.FindProjectItem (fileName) .Properties.Item ("CustomToolNamespace"). Value.ToString ();  
   
    закрытый класс VSManager: Manager {   
        частный EnvDTE.ProjectItem templateProjectItem;  
        частный EnvDTE.DTE dte;  
        приватное действие <String> checkOutAction;  
        закрытое действие <IEnumerable <String >> projectSyncAction;  
   
        public override String DefaultProjectNamespace {   
            get {   
                return templateProjectItem.ContainedProject.Properties.Item ("DefaultNamespace"). Value.ToString ();  
            }   
        }   
   
        public override String GetCustomToolNamespace (string fileName) {   
        }   
   
        public override void Process (bool split) {   
            if (templateProjectItem.ProjectItems == null)   
                возврат;  
            base.Process (сплит);  
            projectSyncAction.EndInvoke (projectSyncAction.BeginInvoke (generateFileNames, null, null));  
        }   
   
        защищенное переопределение void CreateFile (String fileName, String content) {   
            if (IsFileContentDifferent (fileName, content)) {   
                CheckoutFileIfRequired (fileName);  
                File.WriteAllText (fileName, content);  
            }   
        }   
   
        внутренний VSManager (хост ITextTemplatingEngineHost, шаблон StringBuilder)   
            : base (хост, шаблон) {   
            var hostServiceProvider = (IServiceProvider) host;  
            if (hostServiceProvider == null) выдает   
                новое ArgumentNullException ("Не удалось получить IServiceProvider");  
            dte = (EnvDTE.DTE) hostServiceProvider.GetService (typeof (EnvDTE.DTE));  
            if (dte == null)   
                генерирует новое исключение ArgumentNullException («Не удалось получить DTE от хоста»);  
            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 в templateProjectItem.ProjectItems)   
                projectFiles.Add (projectItem.get_FileNames (0), projectItem);  
   
            // Удалить неиспользуемые элементы из проекта   
            foreach (пара var в projectFiles)  
                if (! keepFileNames.Contains (pair.Key) &&! (Path.GetFileNameWithoutExtension (pair.Key) + "."). StartsWith (originalFilePrefix))   
                    pair.Value.Delete ();  
            if (sc! = null && sc.IsItemUnderSCC (fileName) &&! sc.IsItemCheckedOut (fileName))   
                checkOutAction.EndInvoke (checkOutAction.BeginInvoke (fileName, null, null));  
        }  
   
            foreach (String fileName в keepFileNameSet)   
                if (! projectFiles.ContainsKey (fileName))   
                    templateProjectItem.ProjectItems.AddFromFile (fileName);  
        }   
   
        private void CheckoutFileIfRequired (String fileName) {   
            var sc = dte.SourceControl;  
    }   
} #>  

 

Далее, обратитесь к этому шаблону в файле шаблона T4 и объявите экземпляр класса Manager:

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

 

Использование двух строк кода может привести к выводу кода в отдельный файл. Код, который вы хотите вывести, можно записать в середине этих двух операторов. Параметр StartNewFile - это имя выходного файла:

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

 

Например, вы можете написать:

<# manager.StartNewFile ("Employee.generated.cs"); #>   
открытый класс Employee {}   
<# manager.EndBlock (); #>  

 

Вы также можете вывести один и тот же заголовок или верхнюю часть для каждого выходного файла, просто нужно соответствующее выражение:

<# manager.StartHeader (); #>   
// Код, сгенерированный шаблоном   
using System;  
<# manager.EndBlock (); #>   
   
<# manager.StartFooter (); #>   
// Это конец   
<# manager.EndBlock (); #>  

 

Наконец, используйте это предложение для вывода нескольких файлов:

<# manager.Process (true); #>  

 

Опубликовано 17 оригинальных статей · Нравится 230 · Посещений 340 000+

рекомендация

отblog.csdn.net/cxu123321/article/details/105514714
T4