zoukankan      html  css  js  c++  java
  • 从T4模板引擎到自己的代码生成器(1)

    T4模板才接触半个月,但最不满的是它不能方便的脱离vs stuido。如果我要自己写代码生成器,怎么办?

    园子里讲T4模板的不少,但讲如何在自己的程序中使用引擎的很少。查了很久的资料才知道,这东西叫:Text Template Host.

    知道名字,资料就好了。接下来就可以试着建立一个自己的Host.

    (1)写一个最简单的tt文件:

    <#@ template debug="true" hostSpecific="true" #>
    <#@ output extension=".cs" #>

    using System;public class HelloWord{   
     static void Main()    {   
     
      }

    }

    (2)新建一个项目,放个按钮,写点击代码:

     TextCode host = new TextCode();
                //host.Namespace = txtNamespace.Text;
                
    //host.Classname = txtTablemame.Text;
                host.FileExtension = ".cs";
                host.TemplateFile = "Test.tt";

                Microsoft.VisualStudio.TextTemplating.Engine engine = new Microsoft.VisualStudio.TextTemplating.Engine();
                string content = "";
                string input = "";
                string output = "";
                input = System.IO.File.ReadAllText(host.TemplateFile);
                output = engine.ProcessTemplate(input, host);

                string outputname ="newTest" + host.FileExtension;

                System.IO.File.WriteAllText(outputname, output);
               
                string strError="";
                foreach (CompilerError error in host.Errors)
                {
                    strError += error.ToString();
                }
                MessageBox.Show(strError);

    等等,一堆错误。。。那个TextCode 是什么东西?

    (3) TextCode是自己写的一个类,它就是一个 host,需要实现一个TextTemplating.ITextTemplatingEngineHost接口。这个接口非常复杂,我找了一个比较完整的代码来解释。

    using System;
    using System.Collections.Generic;
    using System.Text;
    using System.IO;
    using System.Xml;
    using System.Data;
    using System.CodeDom.Compiler;

    namespace TestForT4.Code
    {
        [Serializable]
        class TextCode : Microsoft.VisualStudio.TextTemplating.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;
                }
            }


            //Passes in the name of a service. If you have that service, you need to 
            
    //pass back a pointer to it. Otherwise, you need to pass back NULL to 
            
    //indicate that you have no knowledge of that service.
            
    //--------------------------------------------------------------------
            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.
            }

        }
    }

    (4)最后呢。。。运行它!不过,如果你要想脱离vs。最好加上它的运行的dll.vs2008中叫Microsoft.VisualStudio.TextTemplating.dll。至于2010呢,两个文件,自己 gg一下吧。

    运行,如果最后的提示是空白,那么就对啦,如果不对。请对着提示找错吧。

  • 相关阅读:
    小程序返回顶部top滚动
    创建对象的几种模式
    前端基础常识
    三行代码让页面中的所有元素增添不同颜色的外边框
    纯css制作小三角
    设计表单
    纯css制作三级菜单
    三栏-中栏流动布局
    三栏固定布局(为栏设定内边距和边框)
    ie8以下不兼容h5新标签的解决方法
  • 原文地址:https://www.cnblogs.com/minttang/p/2185291.html
Copyright © 2011-2022 走看看