首先,保存以下代码为一个模板文件(例如保存文件名为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" #> |
022 |
private class Block { |
024 |
public int Start, Length; |
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>(); |
035 |
public static Manager Create(ITextTemplatingEngineHost host, StringBuilder template) { |
036 |
return (host is IServiceProvider) ? new VSManager(host, template) : new Manager(host, template); |
039 |
public void StartNewFile(String name) { |
041 |
throw new ArgumentNullException( "name" ); |
042 |
CurrentBlock = new Block { Name = name }; |
045 |
public void StartFooter() { |
046 |
CurrentBlock = footer; |
049 |
public void StartHeader() { |
050 |
CurrentBlock = header; |
053 |
public void EndBlock() { |
054 |
if (CurrentBlock == null ) |
056 |
CurrentBlock.Length = template.Length - CurrentBlock.Start; |
057 |
if (CurrentBlock != header && CurrentBlock != footer) |
058 |
files.Add(CurrentBlock); |
062 |
public virtual void Process( bool split) { |
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); |
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); |
079 |
protected virtual void CreateFile(String fileName, String content) { |
080 |
if (IsFileContentDifferent(fileName, content)) |
081 |
File.WriteAllText(fileName, content); |
084 |
public virtual String GetCustomToolNamespace(String fileName) { |
088 |
public virtual String DefaultProjectNamespace { |
092 |
protected bool IsFileContentDifferent(String fileName, String newContent) { |
093 |
return !(File.Exists(fileName) && File.ReadAllText(fileName) == newContent); |
096 |
private Manager(ITextTemplatingEngineHost host, StringBuilder template) { |
098 |
this .template = template; |
101 |
private Block CurrentBlock { |
102 |
get { return currentBlock; } |
104 |
if (CurrentBlock != null ) |
107 |
value.Start = template.Length; |
108 |
currentBlock = value; |
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; |
118 |
public override String DefaultProjectNamespace { |
120 |
return templateProjectItem.ContainingProject.Properties.Item( "DefaultNamespace" ).Value.ToString(); |
124 |
public override String GetCustomToolNamespace( string fileName) { |
125 |
return dte.Solution.FindProjectItem(fileName).Properties.Item( "CustomToolNamespace" ).Value.ToString(); |
128 |
public override void Process( bool split) { |
129 |
if (templateProjectItem.ProjectItems == null ) |
132 |
projectSyncAction.EndInvoke(projectSyncAction.BeginInvoke(generatedFileNames, null , null )); |
135 |
protected override void CreateFile(String fileName, String content) { |
136 |
if (IsFileContentDifferent(fileName, content)) { |
137 |
CheckoutFileIfRequired(fileName); |
138 |
File.WriteAllText(fileName, content); |
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)); |
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); |
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); |
163 |
foreach (var pair in projectFiles) |
164 |
if (!keepFileNames.Contains(pair.Key) && !(Path.GetFileNameWithoutExtension(pair.Key) + "." ).StartsWith(originalFilePrefix)) |
168 |
foreach (String fileName in keepFileNameSet) |
169 |
if (!projectFiles.ContainsKey(fileName)) |
170 |
templateProjectItem.ProjectItems.AddFromFile(fileName); |
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, null , null )); |
接着,在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(); #> |
4 |
<# manager.EndBlock(); #> |
6 |
<# manager.StartFooter(); #> |
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); #>