用T4生成多个文件

首先,保存以下代码为一个模板文件(例如保存文件名为Manager.ttinclude):

001 <#@ assembly name="System.Core"#>
002 <#@ assembly name="System.Data.Linq"#>
003 <#@ assembly name="EnvDTE"#>
004 <#@ assembly name="System.Xml"#>
005 <#@ assembly name="System.Xml.Linq"#>
006 <#@ import namespace="System"#>
007 <#@ import namespace="System.CodeDom"#>
008 <#@ import namespace="System.CodeDom.Compiler"#>
009 <#@ import namespace="System.Collections.Generic"#>
010 <#@ import namespace="System.Data.Linq"#>
011 <#@ import namespace="System.Data.Linq.Mapping"#>
012 <#@ import namespace="System.IO"#>
013 <#@ import namespace="System.Linq"#>
014 <#@ import namespace="System.Reflection"#>
015 <#@ import namespace="System.Text"#>
016 <#@ import namespace="System.Xml.Linq"#>
017 <#@ import namespace="Microsoft.VisualStudio.TextTemplating"#>
018 <#+
019  
020 // Manager class records the various blocks so it can split them up
021 class Manager {
022     private class Block {
023         public String Name;
024         public int Start, Length;
025     }
026  
027     private Block currentBlock;
028     private List<Block> files = new List<Block>();
029     private Block footer = new Block();
030     private Block header = new Block();
031     private ITextTemplatingEngineHost host;
032     private StringBuilder template;
033     protected List<String> generatedFileNames = new List<String>();
034  
035     public static Manager Create(ITextTemplatingEngineHost host, StringBuilder template) {
036         return (host is IServiceProvider) ? new VSManager(host, template) : new Manager(host, template);
037     }
038  
039     public void StartNewFile(String name) {
040         if (name == null)
041             throw new ArgumentNullException("name");
042         CurrentBlock = new Block { Name = name };
043     }
044  
045     public void StartFooter() {
046         CurrentBlock = footer;
047     }
048  
049     public void StartHeader() {
050         CurrentBlock = header;
051     }
052  
053     public void EndBlock() {
054         if (CurrentBlock == null)
055             return;
056         CurrentBlock.Length = template.Length - CurrentBlock.Start;
057         if (CurrentBlock != header && CurrentBlock != footer)
058             files.Add(CurrentBlock);
059         currentBlock = null;
060     }
061  
062     public virtual void Process(bool split) {
063         if (split) {
064             EndBlock();
065             String headerText = template.ToString(header.Start, header.Length);
066             String footerText = template.ToString(footer.Start, footer.Length);
067             String outputPath = Path.GetDirectoryName(host.TemplateFile);
068             files.Reverse();
069             foreach(Block block in files) {
070                 String fileName = Path.Combine(outputPath, block.Name);
071                 String content = headerText + template.ToString(block.Start, block.Length) + footerText;
072                 generatedFileNames.Add(fileName);
073                 CreateFile(fileName, content);
074                 template.Remove(block.Start, block.Length);
075             }
076         }
077     }
078  
079     protected virtual void CreateFile(String fileName, String content) {
080         if (IsFileContentDifferent(fileName, content))
081             File.WriteAllText(fileName, content);
082     }
083  
084     public virtual String GetCustomToolNamespace(String fileName) {
085         return null;
086     }
087  
088     public virtual String DefaultProjectNamespace {
089         get return null; }
090     }
091  
092     protected bool IsFileContentDifferent(String fileName, String newContent) {
093         return !(File.Exists(fileName) && File.ReadAllText(fileName) == newContent);
094     }
095  
096     private Manager(ITextTemplatingEngineHost host, StringBuilder template) {
097         this.host = host;
098         this.template = template;
099     }
100  
101     private Block CurrentBlock {
102         get return currentBlock; }
103         set {
104             if (CurrentBlock != null)
105                 EndBlock();
106             if (value != null)
107                 value.Start = template.Length;
108             currentBlock = value;
109         }
110     }
111  
112     private class VSManager: Manager {
113         private EnvDTE.ProjectItem templateProjectItem;
114         private EnvDTE.DTE dte;
115         private Action<String> checkOutAction;
116         private Action<IEnumerable<String>> projectSyncAction;
117  
118         public override String DefaultProjectNamespace {
119             get {
120                 return templateProjectItem.ContainingProject.Properties.Item("DefaultNamespace").Value.ToString();
121             }
122         }
123  
124         public override String GetCustomToolNamespace(string fileName) {
125             return dte.Solution.FindProjectItem(fileName).Properties.Item("CustomToolNamespace").Value.ToString();
126         }
127  
128         public override void Process(bool split) {
129             if (templateProjectItem.ProjectItems == null)
130                 return;
131             base.Process(split);
132             projectSyncAction.EndInvoke(projectSyncAction.BeginInvoke(generatedFileNames, nullnull));
133         }
134  
135         protected override void CreateFile(String fileName, String content) {
136             if (IsFileContentDifferent(fileName, content)) {
137                 CheckoutFileIfRequired(fileName);
138                 File.WriteAllText(fileName, content);
139             }
140         }
141  
142         internal VSManager(ITextTemplatingEngineHost host, StringBuilder template)
143             base(host, template) {
144             var hostServiceProvider = (IServiceProvider) host;
145             if (hostServiceProvider == null)
146                 throw new ArgumentNullException("Could not obtain IServiceProvider");
147             dte = (EnvDTE.DTE) hostServiceProvider.GetService(typeof(EnvDTE.DTE));
148             if (dte == null)
149                 throw new ArgumentNullException("Could not obtain DTE from host");
150             templateProjectItem = dte.Solution.FindProjectItem(host.TemplateFile);
151             checkOutAction = (String fileName) => dte.SourceControl.CheckOutItem(fileName);
152             projectSyncAction = (IEnumerable<String> keepFileNames) => ProjectSync(templateProjectItem, keepFileNames);
153         }
154  
155         private static void ProjectSync(EnvDTE.ProjectItem templateProjectItem, IEnumerable<String> keepFileNames) {
156             var keepFileNameSet = new HashSet<String>(keepFileNames);
157             var projectFiles = new Dictionary<String, EnvDTE.ProjectItem>();
158             var originalFilePrefix = Path.GetFileNameWithoutExtension(templateProjectItem.get_FileNames(0)) + ".";
159             foreach(EnvDTE.ProjectItem projectItem in templateProjectItem.ProjectItems)
160                 projectFiles.Add(projectItem.get_FileNames(0), projectItem);
161  
162             // Remove unused items from the project
163             foreach(var pair in projectFiles)
164                 if (!keepFileNames.Contains(pair.Key) && !(Path.GetFileNameWithoutExtension(pair.Key) + ".").StartsWith(originalFilePrefix))
165                     pair.Value.Delete();
166  
167             // Add missing files to the project
168             foreach(String fileName in keepFileNameSet)
169                 if (!projectFiles.ContainsKey(fileName))
170                     templateProjectItem.ProjectItems.AddFromFile(fileName);
171         }
172  
173         private void CheckoutFileIfRequired(String fileName) {
174             var sc = dte.SourceControl;
175             if (sc != null && sc.IsItemUnderSCC(fileName) && !sc.IsItemCheckedOut(fileName))
176                 checkOutAction.EndInvoke(checkOutAction.BeginInvoke(fileName, nullnull));
177         }
178     }
179 } #>

接着,在T4模板文件里引用这个模板,并声明一个Manager类实例:

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

使用两行代码可使代码输出到单独文件,你要输出的代码可写在这两个语句中间,StartNewFile的参数就是输出的文件名:

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

比如可以这样写:

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

还可以为每个输出文件输出同样的头部或顶部,只需要相应的语句:

1 <# manager.StartHeader(); #>
2 // Code generated by a template
3 using System;
4 <# manager.EndBlock(); #>
5  
6 <# manager.StartFooter(); #>
7 // It's the end
8 <# manager.EndBlock(); #>

最后使用这句来执行输出多个文件:

1 <# manager.Process(true); #>
<#@ template debug="false" hostspecific="true" language="C#" #>

<#@ import namespace="System.IO" #>

<#@ include file="manager.ttinclude"#>

<# var manager = new Manager(Host, GenerationEnvironment, true) { OutputPath = Path.GetDirectoryName(Host.TemplateFile) }; #>




<# 
    string ClassNames = "AdminPurview,AdminLog,AdminUser";
    foreach(string ClassName in ClassNames.Split(char.Parse(",")) ){
#>

  <# manager.StartBlock(ClassName+"Repository.cs"); #> 


using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using DAL.Entities;
using DAL.Infrastructure;
using DAL.Repository;

namespace Repositories
{
 
    public class <#=ClassName #>Repository : RepositoryBase<<#=ClassName#>>, ICategoryRepository
    {
        public <#=ClassName #>Repository(DatabaseFactory databaseFactory)
            : base(databaseFactory)
        {
        }
    }
    public interface I<#=ClassName #>Repository : IRepository<<#=ClassName#>>
    {
    }


}
<# manager.EndBlock(); #>
<#}#>
<# manager.Process(true); #>

  

posted @ 2011-10-04 15:48  coding111  阅读(726)  评论(3)    收藏  举报