first, the definition of T4 template and the generation of code files
Let's take a look at what the final code generation needs to define, and how the T4 template should be defined. For this framework, the generation of code structures is implemented by inheriting custom types from our custom base class template. As a demo, we define a demotemplate as follows. As you can see from the code, Demotemplate is only used to generate an empty class, and the type name is specified in the constructor.
1: Public class Demotemplate:template
2: {
3: Public string ClassName {get; private set;}
4: Public demotemplate (string className)
5: {
6: This . ClassName = ClassName;
7: }
8: Public override string TransformText ()
9: {
A: this . WriteLine (' public class {0} ', this. ClassName);
One: this . WriteLine ("{");
A: this . WriteLine ("}");
return this . Generationenvironment.tostring ();
: }
: }
The generation of the code is finally implemented by performing the corresponding generator, for which we define the following demogenerator. Demogenerator eventually generates three. cs files, and the code for each file is ultimately generated by the demotemplate defined above. As the following code fragment shows, the Demogenerator inherited from generator overrides the Createtemplates method and returns a Dictionary object. The key of the dictionary represents the generated file name, and value represents the corresponding Template object.
1: Public class Demogenerator:generator
2: {
3: protected override idictionary<string, Template> createtemplates ()
4: {
5: dictionary<string, template> templates = new dictionary<string, template> ();
6: templates. ADD ("Foo.cs", New Demotemplate ("Foo"));
7: templates. ADD ("Bar.cs", New Demotemplate ("Bar"));
8: templates. ADD ("Baz.cs", New Demotemplate ("Baz"));
9: Return templates;
: }
One: }
Finally, we execute the demogenerator in the T4 file to generate the three. cs files we need.
1: <#@ template hostspecific= "true" language= "C #" #>
2: <#@ Assembly Name= "$ (TargetDir) Artech.CodeGeneration.dll" #>
3: <#@ import namespace= "Artech.codegeneration" #>
4: <#@ output extension= ". Empty" #>
5: <#
6: This . Runcodegenerator (this. Host, New Demogenerator ());
7: #>
Three. cs files (Foo.cs, Bar.cs, and Baz.cs) will eventually be generated in the following manner.
ii. Transformationcontext and Transformationcontextscope
Let's take a quick look at how generator ultimately uses template to generate the corresponding text file. But before we do, let's take a look at the two types of Transformationcontext and Transformationcontextscope. As the name suggests, Transformationcontext is used to store contextual information for T4 text transformations, and transformationcontextscope is used to limit the scope of the Transformationcontext. This is the same as the transaction/transactionscope relationship.
The Transformationcontext definition is as follows: The static property current represents the present Transformationcontext, through which you can get the current texttransformation (That is, the T4 file itself corresponds to the Texttransformation object), the current texttemplatingenginehost, and the DTE and ProjectItem for T4 files.
1: Public class Transformcontext
2: {
3: Public static Transformcontext current {get; internal set;}
4: Public texttransformation transformation{get; private set;}
5: Public itexttemplatingenginehost Host {get; private set;}
6: Public DTE DTE {get; private set;}
7: Public ProjectItem Templateprojectitem {get; private set;}
8:
9: Internal Transformcontext (texttransformation transformation, itexttemplatingenginehost host)
%: {
One: this . Transformation = transformation;
A: this . host = host;
: This . DTE = (DTE) ((IServiceProvider) host). GetService (typeof (DTE));
A: this . Templateprojectitem = this. Dte.Solution.FindProjectItem (host. TemplateFile);
: }
:
: public static void Ensurecontextinitialized ()
: {
: if (null = = current)
: {
throw new Transformationexception ("Transformcontext is not initialized.");
: }
: }
: }
Transformationcontext constructors are internal, so they cannot be built directly from outside, We create it by transformationcontextscope with the following definition as the current transformationcontext. The Transformationcontextscope implements the IDisposable interface, and the current Transformationcontext in the implemented Dispose method is set to null.
1: Public class Transformcontextscope:idisposable
2: {
3: Public Transformcontextscope (texttransformation transformation, itexttemplatingenginehost host)
4: {
5: transformcontext.current = new Transformcontext (transformation, host);
6: }
7:
8: Public void Dispose ()
9: {
Ten: transformcontext.current = null;
One: }
: }
Third, Template
The logical implementation of code generation is inherited from a template type that has the following definition, and it is a subclass of Texttransformation. The core of template is the render and rendertofile method, which means that the generated code is written to the corresponding build file of the T4 file, which writes the content to a specified file. The code generated by template is obtained by calling TransformText, and the T4 object represented by the Texttransformation file itself is obtained directly through the current Transformcontext in the Render method. and calls its Wirte method to write the content.
The Rendertofile method is relatively complex because it involves generating new files. It first obtains the texttemplatingenginehost by the current Transformcontext and calculates the T4 directory, and finally resolves the final path of the generated file. File creation and content writes are implemented by calling the CreateFile method, and if source control is involved, a check out operation is also required. The newly created file is eventually added to project by the ProjectItem object that represents the T4 file.
1: Public abstract class Template:texttransformation
2: {