転送元:http : //blog.csdn.net/cracklibby/article/details/51319799
T4を最初に認識してコードを生成しようとしたとき、関連する学習教材は比較的少ないようです。ただし、VS2010のMSDNには関連する章があります。「コード生成とテキストテンプレート」の章を参照できます。テンプレートは、C#構文で記述できます。
T4が複数のファイルを生成するのが難しいことがすぐに明らかになり、Microsoftはこれを改善するために急いでいるようには見えませんでした。検索の結果、InfoQから「T4で複数のファイルを生成する」という記事が見つかりました。この記事にリンクすると、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 { private class Block { public String Name; public int Start、Length; } プライベートブロックcurrentBlock; private List <Block> files = new List <Block>(); プライベートブロックフッター= new Block(); プライベートブロックヘッダー= new Block(); プライベートITextTemplatingEngineHostホスト。 プライベートStringBuilderテンプレート。 保護されたリスト<文字列> generatedFileNames =新しいリスト<文字列>(); public static Manager Create(ITextTemplatingEngineHost host、StringBuilder template){ return(host is IServiceProvider)?新しいVSManager(host、template):新しいManager(host、template); } 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!= 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); 文字列footerText = template.ToString(footer.Start、footer.Length); String outputPath = Path.GetDirectoryName(host.TemplateFile); files.Reverse(); foreach(ファイル内のブロックをブロック){ 文字列fileName = Path.Combine(outputPath、block.Name); 文字列コンテンツ= 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); } プライベートマネージャー(ITextTemplatingEngineHostホスト、StringBuilderテンプレート){ this.host = host; this.template =テンプレート; } private Block CurrentBlock { get {return currentBlock; } セット{ if(CurrentBlock!= null) EndBlock(); if(value!= null) value.Start = template.Length; currentBlock = value; } } プライベートクラスVSManager:マネージャー{ プライベートEnvDTE.ProjectItem templateProjectItem; プライベートEnvDTE.DTE dte; プライベートAction <String> checkOutAction; プライベート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)); } 保護されたオーバーライドvoid CreateFile(String fileName、String content){ if(IsFileContentDifferent(fileName、content)){ CheckoutFileIfRequired(fileName); File.WriteAllText(fileName、content); } } 内部VSManager(ITextTemplatingEngineHostホスト、StringBuilderテンプレート) :base(host、template){ var hostServiceProvider =(IServiceProvider)host; if(hostServiceProvider == null) throw new ArgumentNullException( "IServiceProviderを取得できませんでした"); dte =(EnvDTE.DTE)hostServiceProvider.GetService(typeof(EnvDTE.DTE)); if(dte == null) throw new ArgumentNullException( "ホストからDTEを取得できませんでした"); templateProjectItem = dte.Solution.FindProjectItem(host.TemplateFile); checkOutAction =(String fileName)=> dte.SourceControl.CheckOutItem(fileName); projectSyncAction =(IEnumerable <String> keepFileNames)=> ProjectSync(templateProjectItem、keepFileNames); } プライベート静的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); //未使用のアイテムをプロジェクトから削除します foreach(varFile in projectFiles) if(!keepFileNames.Contains(pair.Key)&&!(Path.GetFileNameWithoutExtension(pair.Key)+ "。")。StartsWith(originalFilePrefix)) pair.Value.Delete(); 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)); } } }#>
次に、T4テンプレートファイルでこのテンプレートを参照し、Managerクラスのインスタンスを宣言します。
<#@ template language = "C#" hostspecific = "True"#> <#@ include file = "Manager.ttinclude"#> <#var manager = Manager.Create(Host、GenerationEnvironment); #>
2行のコードを使用すると、コードを別のファイルに出力できます。出力するコードは、次の2つのステートメントの途中で記述できます。StartNewFileのパラメーターは、出力ファイルの名前です。
<#manager.StartNewFile( "Employee.generated.cs"); #> <#manager.EndBlock(); #>
たとえば、次のように書くことができます。
<#manager.StartNewFile( "Employee.generated.cs"); #> public class Employee {} <#manager.EndBlock(); #>
各出力ファイルに同じヘッダーまたはトップを出力することもできます。対応するステートメントが必要です。
<#manager.StartHeader(); #> // システムを使用してテンプレートによって生成されたコード ; <#manager.EndBlock(); #> <#manager.StartFooter(); #> //これで終わりです <#manager.EndBlock(); #>
最後にこの文を使用して、複数のファイルの出力を実行します。
<#manager.Process(true); #>