【转】- 使用T4模板批量生成代码

前言

     之前在 “使用T4模板生成代码 - 初探” 文章简单的使用了T4模板的生成功能,但对于一个模板生成多个实例文件,如何实现这个方式呢?无意发现一个解决方案 “MultipleOutputHelper.ttinclude” ,它让基于T4模板批量生成文件实例变得简单起来了。

 

 什么是MultipleOutputHelper.ttinclude

     Damien Guard是一个在加利福尼亚州圣何塞的开发人员,他构建出处理使用T4模板输出多文件的解决方案“MultipleOutputHelper.ttinclude”

 

 使用

      1. 初始化

     获取MultipleOutputHelper.ttinclude文件模板

     注意: 文件可以上github.com 托管上面获取( https://github.com/damieng/DamienGKit/tree/master/T4/MultipleOutputHelper

     在T4模板中使用include指令导入MultipleOutputHelper.ttinclude文件或者将MultipleOutputHelper.ttinclude的代码复制在T4模板内。

     然后初始化Manager对象,代码如下:

     

     注意: 这里的Manager.ttinclude 就是MultipleOutputHelper.ttinclude文件模板     

 

     2. 文件块

     使用代码标识区分生成的代码块的范围

     

     该代码声明了一个Employee.generated.cs文件,文件代码内容为:

     

1
public  class  Employee { ... }

 

     3. 页眉和页脚

     很多模板需要共享一个共同的页眉和页脚时,可以使用import语句进行打开和关闭。简单的使用StartHeader和StartFooter的代码方法进行分割。

     

     4. 编译执行

    使用Process方法,进行文件分割。

    

 

  场景应用

    基于之前的“使用T4模板生成代码 - 初探” 文章的场景,进行基于NHibernate Mapper 来获取Domain对象,然后进行批量生成多个代码文件。

    1. 自定义T4模板,文件名为“EntityRepositoryTemplate.tt”,代码如下:

    

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
<#@ template  language= "C#"     debug= "true"  hostspecific= "True" #>
//  导入MultipleOutputHelper.ttinclude文件
<#@include file= "$(SolutionDir)app\T4\MultipleOutputHelper.ttinclude" #>
// 导入相关的DLL
<#@ Assembly Name= "$(SolutionDir)lib\SharpArch.2.0.2\NHibernate.dll"  #>
<#@ Assembly Name= "$(SolutionDir)lib\SharpArch.2.0.2\SharpArch.NHibernate.dll"  #>
<#@ Assembly Name= "$(SolutionDir)lib\SharpArch.2.0.2\SharpArch.Domain.dll"  #>
<#@ Assembly Name= "$(SolutionDir)lib\SharpArch.2.0.2\FluentNHibernate.dll"  #>
<#@ Assembly Name= "$(SolutionDir)app\Cotide.Data\bin\$(ConfigurationName)\Cotide.Infrastructure.dll"  #>
<#@ Assembly Name= "$(SolutionDir)app\Cotide.Core\bin\$(ConfigurationName)\Cotide.Domain.dll"  #>
<#@ Assembly Name= "$(SolutionDir)app\Cotide.Framework\bin\$(ConfigurationName)\Cotide.Framework.dll"  #>
<#@ import namespace = "System.IO" #>
<#@ import namespace = "System" #>
<#@ import namespace = "System.Configuration" #>  
  <# 
     // 初始化
     SharpArch.NHibernate.NHibernateSession.CloseAllSessions();
     SharpArch.NHibernate.NHibernateSession.Reset();
     string  projectPath = @"C:\资料\Person\项目\Codeplex\电子商务\app\" ;
     string  nhibernatePath = projectPath + @"Cotide.Web\NHibernate.config" ;
     string [] mappingAssemblies = new [] { @"C:\资料\Person\项目\Codeplex\电子商务\app\Cotide.Data\bin\Release\Cotide.Infrastructure.dll"  };
     // 加载配置
     NHibernate.Cfg.Configuration configuration = SharpArch.NHibernate.NHibernateSession.Init(
     new  SharpArch.NHibernate.SimpleSessionStorage(), mappingAssemblies,
     new  Cotide.Infrastructure.NHibernateMaps.AutoPersistenceModelGenerator().Generate(),
     nhibernatePath);
     // 获取所有类映射
     var allClassMetadata = SharpArch.NHibernate.NHibernateSession.GetDefaultSessionFactory().GetAllClassMetadata();
     var manager = Manager.Create(Host, GenerationEnvironment); 
     foreach  (var entry in  allClassMetadata)
     {
        var entityName = entry.Value.EntityName.Split( '.' );
        var className = entityName[entityName.Length - 1];
         // 定义输出文件
         manager.StartNewFile( "I" +className+ "Repository.cs" );
        #>//-------------------------------------------------------------------
//版权所有:版权所有(C) 2012,Microsoft(China) Co.,LTD
//系统名称:
//文件名称:I<#=className#>Repository.cs
//模块名称:
//模块编号:
//作  者:xcli
//创建时间:2013/4/6 12:49:50
//功能说明:
//-----------------------------------------------------------------
//修改记录:
//修改人:  
//修改时间:
//修改内容:
//----------------------------------------------------------------- 
using  System;
using  System.Collections.Generic;
using  System.Linq;
using  System.Text;
using  Cotide.Domain.Contracts.Repositories.Extension;
namespace  Cotide.Domain.Contracts.Repositories
{
         public  interface  I<#=className#>Repository : IDbProxyRepository<<#=className#>>
         {
 
         }
}
    <#
        // 结束输出文件
        manager.EndBlock();
     }
        // 执行编译
        manager.Process( true ); 
     #>

 

     输出文件效果:

     

 

 让程序自动执行基于T4文件的编译工作

   在MSDN-”演练:创建自定义文本模板宿主“ 文章里面看到一段代码,进行了T4文件的编译工作,代码如下:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
using  System;
using  System.IO;
using  System.CodeDom.Compiler;
using  System.Collections.Generic;
using  System.Text;
using  Microsoft.VisualStudio.TextTemplating;
 
namespace  CustomHost
{
     //The text template transformation engine is responsible for running
     //the transformation process.
     //The host is responsible for all input and output, locating files,
     //and anything else related to the external environment.
     //-------------------------------------------------------------------------
     class  CustomCmdLineHost : ITextTemplatingEngineHost
     {
         //the path and file name of the text template that is being processed
         //---------------------------------------------------------------------
         internal  string  TemplateFileValue;
         public  string  TemplateFile
         {
             get  { return  TemplateFileValue; }
         }
         //This will be the extension of the generated text output file.
         //The host can provide a default by setting the value of the field here.
         //The engine can change this value based on the optional output directive
         //if the user specifies it in the text template.
         //---------------------------------------------------------------------
         private  string  fileExtensionValue = ".txt" ;
         public  string  FileExtension
         {
             get  { return  fileExtensionValue; }
         }
         //This will be the encoding of the generated text output file.
         //The host can provide a default by setting the value of the field here.
         //The engine can change this value based on the optional output directive
         //if the user specifies it in the text template.
         //---------------------------------------------------------------------
         private  Encoding fileEncodingValue = Encoding.UTF8;
         public  Encoding FileEncoding
         {
             get  { return  fileEncodingValue; }
         }
         //These are the errors that occur when the engine processes a template.
         //The engine passes the errors to the host when it is done processing,
         //and the host can decide how to display them. For example, the host
         //can display the errors in the UI or write them to a file.
         //---------------------------------------------------------------------
         private  CompilerErrorCollection errorsValue;
         public  CompilerErrorCollection Errors
         {
             get  { return  errorsValue; }
         }
         //The host can provide standard assembly references.
         //The engine will use these references when compiling and
         //executing the generated transformation class.
         //--------------------------------------------------------------
         public  IList< string > StandardAssemblyReferences
         {
             get
             {
                 return  new  string []
                 {
                     //If this host searches standard paths and the GAC,
                     //we can specify the assembly name like this.
                     //---------------------------------------------------------
                     //"System"
 
                     //Because this host only resolves assemblies from the
                     //fully qualified path and name of the assembly,
                     //this is a quick way to get the code to give us the
                     //fully qualified path and name of the System assembly.
                     //---------------------------------------------------------
                     typeof (System.Uri).Assembly.Location
                 };
             }
         }
         //The host can provide standard imports or using statements.
         //The engine will add these statements to the generated
         //transformation class.
         //--------------------------------------------------------------
         public  IList< string > StandardImports
         {
             get
             {
                 return  new  string []
                 {
                     "System"
                 };
             }
         }
         //The engine calls this method based on the optional include directive
         //if the user has specified it in the text template.
         //This method can be called 0, 1, or more times.
         //---------------------------------------------------------------------
         //The included text is returned in the context parameter.
         //If the host searches the registry for the location of include files,
         //or if the host searches multiple locations by default, the host can
         //return the final path of the include file in the location parameter.
         //---------------------------------------------------------------------
         public  bool  LoadIncludeText( string  requestFileName, out  string  content, out  string  location)
         {
             content = System.String.Empty;
             location = System.String.Empty;
        
             //If the argument is the fully qualified path of an existing file,
             //then we are done.
             //----------------------------------------------------------------
             if  (File.Exists(requestFileName))
             {
                 content = File.ReadAllText(requestFileName);
                 return  true ;
             }
             //This can be customized to search specific paths for the file.
             //This can be customized to accept paths to search as command line
             //arguments.
             //----------------------------------------------------------------
             else
             {
                 return  false ;
             }
         }
         //Called by the Engine to enquire about
         //the processing options you require.
         //If you recognize that option, return an
         //appropriate value.
         //Otherwise, pass back NULL.
         //--------------------------------------------------------------------
         public  object  GetHostOption( string  optionName)
         {
         object  returnObject;
         switch  (optionName)
         {
         case  "CacheAssemblies" :
                     returnObject = true ;
      break ;
         default :
         returnObject = null ;
         break ;
         }
         return  returnObject;
         }
         //The engine calls this method to resolve assembly references used in
         //the generated transformation class project and for the optional
         //assembly directive if the user has specified it in the text template.
         //This method can be called 0, 1, or more times.
         //---------------------------------------------------------------------
         public  string  ResolveAssemblyReference( string  assemblyReference)
         {
             //If the argument is the fully qualified path of an existing file,
             //then we are done. (This does not do any work.)
             //----------------------------------------------------------------
             if  (File.Exists(assemblyReference))
             {
                 return  assemblyReference;
             }
             //Maybe the assembly is in the same folder as the text template that
             //called the directive.
             //----------------------------------------------------------------
             string  candidate = Path.Combine(Path.GetDirectoryName( this .TemplateFile), assemblyReference);
             if  (File.Exists(candidate))
             {
                 return  candidate;
             }
             //This can be customized to search specific paths for the file
             //or to search the GAC.
             //----------------------------------------------------------------
             //This can be customized to accept paths to search as command line
             //arguments.
             //----------------------------------------------------------------
             //If we cannot do better, return the original file name.
             return  "" ;
         }
         //The engine calls this method based on the directives the user has
         //specified in the text template.
         //This method can be called 0, 1, or more times.
         //---------------------------------------------------------------------
         public  Type ResolveDirectiveProcessor( string  processorName)
         {
             //This host will not resolve any specific processors.
             //Check the processor name, and if it is the name of a processor the
             //host wants to support, return the type of the processor.
             //---------------------------------------------------------------------
             if  ( string .Compare(processorName, "XYZ" , StringComparison.OrdinalIgnoreCase) == 0)
             {
                 //return typeof();
             }
             //This can be customized to search specific paths for the file
             //or to search the GAC
             //If the directive processor cannot be found, throw an error.
             throw  new  Exception( "Directive Processor not found" );
         }
         //A directive processor can call this method if a file name does not
         //have a path.
         //The host can attempt to provide path information by searching
         //specific paths for the file and returning the file and path if found.
         //This method can be called 0, 1, or more times.
         //---------------------------------------------------------------------
         public  string  ResolvePath( string  fileName)
         {
             if  (fileName == null )
             {
                 throw  new  ArgumentNullException( "the file name cannot be null" );
             }
             //If the argument is the fully qualified path of an existing file,
             //then we are done
             //----------------------------------------------------------------
             if  (File.Exists(fileName))
             {
                 return  fileName;
             }
             //Maybe the file is in the same folder as the text template that
             //called the directive.
             //----------------------------------------------------------------
             string  candidate = Path.Combine(Path.GetDirectoryName( this .TemplateFile), fileName);
             if  (File.Exists(candidate))
             {
                 return  candidate;
             }
             //Look more places.
             //----------------------------------------------------------------
             //More code can go here...
             //If we cannot do better, return the original file name.
             return  fileName;
         }
         //If a call to a directive in a text template does not provide a value
         //for a required parameter, the directive processor can try to get it
         //from the host by calling this method.
         //This method can be called 0, 1, or more times.
         //---------------------------------------------------------------------
         public  string  ResolveParameterValue( string  directiveId, string  processorName, string  parameterName)
         {
             if  (directiveId == null )
             {
                 throw  new  ArgumentNullException( "the directiveId cannot be null" );
             }
             if  (processorName == null )
             {
                 throw  new  ArgumentNullException( "the processorName cannot be null" );
             }
             if  (parameterName == null )
             {
                 throw  new  ArgumentNullException( "the parameterName cannot be null" );
             }
             //Code to provide "hard-coded" parameter values goes here.
             //This code depends on the directive processors this host will interact with.
             //If we cannot do better, return the empty string.
             return  String.Empty;
         }
         //The engine calls this method to change the extension of the
         //generated text output file based on the optional output directive
         //if the user specifies it in the text template.
         //---------------------------------------------------------------------
         public  void  SetFileExtension( string  extension)
         {
             //The parameter extension has a '.' in front of it already.
             //--------------------------------------------------------
             fileExtensionValue = extension;
         }
         //The engine calls this method to change the encoding of the
         //generated text output file based on the optional output directive
         //if the user specifies it in the text template.
         //----------------------------------------------------------------------
         public  void  SetOutputEncoding(System.Text.Encoding encoding, bool  fromOutputDirective)
         {
             fileEncodingValue = encoding;
         }
         //The engine calls this method when it is done processing a text
         //template to pass any errors that occurred to the host.
         //The host can decide how to display them.
         //---------------------------------------------------------------------
         public  void  LogErrors(CompilerErrorCollection errors)
         {
             errorsValue = errors;
         }
         //This is the application domain that is used to compile and run
         //the generated transformation class to create the generated text output.
         //----------------------------------------------------------------------
         public  AppDomain ProvideTemplatingAppDomain( string  content)
         {
             //This host will provide a new application domain each time the
             //engine processes a text template.
             //-------------------------------------------------------------
             return  AppDomain.CreateDomain( "Generation App Domain" );
             //This could be changed to return the current appdomain, but new
             //assemblies are loaded into this AppDomain on a regular basis.
             //If the AppDomain lasts too long, it will grow indefintely,
             //which might be regarded as a leak.
             //This could be customized to cache the application domain for
             //a certain number of text template generations (for example, 10).
             //This could be customized based on the contents of the text
             //template, which are provided as a parameter for that purpose.
         }
     }
     //This will accept the path of a text template as an argument.
     //It will create an instance of the custom host and an instance of the
     //text templating transformation engine, and will transform the
     //template to create the generated text output file.
     //-------------------------------------------------------------------------
     class  Program
     {
         static  void  Main( string [] args)
         {
             try
             {
                 ProcessTemplate(args);
             }
             catch  (Exception ex)
             {
                 Console.WriteLine(ex.Message);
             }
         }
         static  void  ProcessTemplate( string [] args)
         {
             string  templateFileName = null ;
             if  (args.Length == 0)
             {
                 throw  new  System.Exception( "you must provide a text template file path" );
             }
             templateFileName = args[0];
             if  (templateFileName == null )
             {
                 throw  new  ArgumentNullException( "the file name cannot be null" );
             }
             if  (!File.Exists(templateFileName))
             {
                 throw  new  FileNotFoundException( "the file cannot be found" );
             }
             CustomCmdLineHost host = new  CustomCmdLineHost();
             Engine engine = new  Engine();
             host.TemplateFileValue = templateFileName;
             //Read the text template.
             string  input = File.ReadAllText(templateFileName);
             //Transform the text template.
             string  output = engine.ProcessTemplate(input, host);
             string  outputFileName = Path.GetFileNameWithoutExtension(templateFileName);
             outputFileName = Path.Combine(Path.GetDirectoryName(templateFileName), outputFileName);
             outputFileName = outputFileName + "1"  + host.FileExtension;
             File.WriteAllText(outputFileName, output, host.FileEncoding);
 
             foreach  (CompilerError error in  host.Errors)
             {
                 Console.WriteLine(error.ToString());
             }
         }
     }
}

    联想:基于这个代码实例,可以做一个基于T4模板来批量输出代码的小工具,待续.....

 

 参考资料

 

转自 http://www.cnblogs.com/K_tommy/archive/2013/04/06/T4.html  

转载于:https://www.cnblogs.com/slow/p/3611216.html

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
### 回答1: VS Code T4 模板是一种用于生成 JavaScript 代码的工具。它基于 T4(Text Template Transformation Toolkit)技术,允许开发者定义模板并在生成代码时将其应用于指定的数据。 使用 VS Code T4 模板生成 JavaScript 代码非常简单。首先,我们需要安装 "T4" 扩展插件,该插件提供了 T4 模板引擎的支持。安装完成后,我们可以创建一个新的 T4 模板文件,并在其中编写模板代码T4 模板使用一种特殊的标记语法,类似于 HTML 的标签。我们可以在模板中定义变量、循环、判断等逻辑,并根据需要生成相应的 JavaScript 代码模板还可以包含外部引用的文件或库,以便在代码生成过程中使用。 一旦模板编写完成,我们可以在模板文件上右键点击,并选择 "运行 T4 模板" 选项,或使用命令面板搜索并运行相应命令。这将触发模板引擎执行,根据模板和提供的数据生成 JavaScript 代码T4 模板可以根据我们定义的逻辑和数据生成任意数量的 JavaScript 代码文件。这为我们提供了一种自动化生成重复代码的方式,在项目开发中可以极大地提高效率和代码质量。 总之,VS Code T4 模板提供了一种方便的方式来生成 JavaScript 代码。通过定义模板和提供相应的数据,我们可以自动生成符合需求的 JavaScript 代码,减少重复工作并提高开发效率。无论是创建新项目、添加新功能还是生成测试数据,T4 模板都能为我们提供一种强大的辅助工具。 ### 回答2: VSCode是一款功能强大的文本编辑器,它提供了许多扩展插件,其中包括T4模板生成JS。T4模板是一种用于生成代码模板引擎,它使用C#或VB.NET编写模板代码,并通过内置的代码生成引擎将模板代码换为最终的输出。 在VSCode中使用T4模板生成JS非常简单。首先,我们需要安装T4模板插件。可以通过在VSCode的扩展商店中搜索"T4 Template"来找到并安装这个插件。安装完成后,我们可以在VSCode的侧边栏中找到T4模板生成器的图标。 接下来,我们需要创建一个T4模板文件。可以使用`.tt`作为扩展名来命名文件,并打开该文件进行编辑。在模板文件中,我们可以使用C#或VB.NET编写代码块,并使用特定的语法来控制模板生成的过程。我们可以定义输入参数、循环结构、条件语句等,以生成不同的输出内容。 在T4模板生成JS代码的过程与生成其他类型的代码并无太大区别。我们可以在模板中定义JS变量、函数、类等,并使用T4模板提供的代码生成功能来生成相应的JS代码。 当模板文件中的代码编写完成后,我们可以保存文件并触发模板生成过程。在VSCode的命令面板中,输入"T4 Template"并选择生成模板命令,就可以将模板文件换为对应的JS代码文件。 总结来说,使用VSCode的T4模板插件可以方便地生成JS代码。我们只需要编写模板文件,定义所需的JS代码结构和逻辑,然后由T4模板生成器自动换为最终的JS代码文件。这样,我们可以更高效地生成大量的JS代码,并减少手工编写的工作量。 ### 回答3: VSCode是一款功能强大的代码编辑器,它支持通过T4模板生成JavaScript代码T4模板是一种文本生成引擎,它允许我们根据定义的模板规则生成特定的代码文件。在VSCode中使用T4模板生成JavaScript代码可以提高开发效率和代码质量。 首先,我们需要安装VSCode的T4模板插件,可以在VSCode的插件市场中搜索并安装。安装完成后,我们可以在VSCode的扩展面板中找到并启用T4模板相关功能。 接下来,在VSCode中创建一个新的文件,并将其命名为T4模板文件,通常以.tt作为文件扩展名。在T4模板文件中,我们可以使用类似于ASP.NET的标签语法来定义模板中的输入和输出。 在模板文件中,我们可以定义输入参数,例如要生成的JavaScript文件的名称和路径。然后,可以使用T4模板提供的标签和指令,通过循环、条件语句和字符串操作等方式来生成JavaScript代码使用T4模板生成JavaScript代码的好处是我们可以根据不同的需求和条件生成不同的代码。这样可以提高代码的可维护性和复用性。同时,T4模板还支持自定义函数和引用外部库,可以更灵活地生成JavaScript代码。 最后,我们可以通过执行模板文件生成JavaScript代码。在VSCode中,我们可以打开T4模板文件,右键点击并选择“换为输出文件”,这将会根据模板文件的定义生成相应的JavaScript代码文件。 总结起来,通过VSCode的T4模板插件,我们可以方便地生成JavaScript代码。通过定义模板规则和执行模板文件,我们可以根据需求快速生成高质量的JavaScript代码。这对于JavaScript开发者来说是一个非常有用的工具。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值