在程序中动态执行T4模板及参数传递|.Net开发|码途山海.智隐长卷 -

程序人生|重庆纽新

找回密码
立即注册

QQ登录

只需一步,快速开始

欢迎访问【程序人生-重庆纽新】,本网站为软件开发人员视觉的IT资讯、软件开发中各种问题的解决办法!!
搜索
发新帖


2308

积分

0

好友

259

主题
楼主
发表于 2015-4-14 11:49:05 | 查看: 4522| 回复: 0
T4模板Visual Studio IDE的应用越来越多,现在在VS中,只要与代码生成相关的场景,我们都可以通过修改 T4模板来自定义生成格式,比如MVC的视图模板,Entity Framwork的DataContext模板等等。同时我们还可以自己创建T4模板文件(.tt),使用C#(VB)语法来编写T4模板,它的语法与ASP.NET的语法非常类似,大大降低了.NET程序员的学习成本,关于T4的模板的更多细节请阅读Oleg Sych关于T4的博客文章。
T4模板,除了静态执行输出之外,我们还可以通过程序动态执行并输出。关于动态执行T4模板,可以参考用程序执行 t4 文件Walkthrough: Creating a Custom Text Template Host,这两篇文章。
这两篇文章都讲到,我们要动态执行T4模板,需要自己定义一个ITextTemplatingEngineHost实现类,并在执行时,将它传给T4引擎:
  1. CustomCmdLineHost host = new CustomCmdLineHost();
  2. Engine engine = new Engine();
  3. host.TemplateFileValue = templateFileName;
  4. string input = File.ReadAllText(templateFileName);
  5. string output = engine.ProcessTemplate(input, host);
复制代码
    很简单,我们就可以动态执行T4模板。但是,如何传递参数给模板的运行时?以上的介绍中并没有提及,变量是模板引擎的血液,而以上的两篇文章刚好都没有介绍到如何传递变量给T4引擎上下文。花了几个小时,终于在找到一点线索,T4中,parameter这个声明的作用和运行原理,它也直接告诉我如何去在运行时传递参数给T4引擎上下文。
    简单的总结一下:我们可以通过两种方式经T4模板传递上下文,分别是通过CallContext和ITextTemplatingSession对象。通过CallContext传递对象要特别注意的是,当前宿主程序的执行上下文和T4模板引擎上下文是不同的,我们可以通过CallContext.LogicalSetData这个方法来将本地对象传递到另一个上下文使用。另一种办法就是通过传递Session对象的方式,这个Session的概念跟ASP.NET的Session概念很相似,它是一个IDictionary<string,object>对象,它允许我们可以定义一些全局变量,供T4引擎上下文使用。那么,同样的问题是,在宿主上下文中,我们如何将Session传递到T4上下文呢?看这段代码:
  1. var sessionHost = (ITextTemplatingSessionHost) this.Host;
  2. sessionHost.Session = session;
复制代码
    也就是在标准的Host对象实现中,除了实现ITextTemplatingEngineHost,还需实现ITextTemplatingSessionHost这个接口,这个接口就会带有一个Session属性的定义。我们就可以通过给这个Session赋值来达到参数传递的目的。这个设想,我们也可以在Engine的内部代码中得到验证:
  1. private static void InitializeSessionWithHostData(ITextTemplatingEngineHost host, TemplateProcessingSession session)
  2. {
  3.     try
  4.     {
  5.         session.TemplateFile = host.TemplateFile;
  6.     }
  7.     catch (NotImplementedException)
  8.     {
  9.         session.TemplateFile = string.Empty;
  10.     }
  11.     session.IncludeStack.Push(session.TemplateFile);
  12.     ITextTemplatingSessionHost host2 = host as ITextTemplatingSessionHost;
  13.     if (host2 != null)
  14.     {
  15.         session.UserTransformationSession = host2.Session;
  16.     }
  17. }
复制代码
    InitializeSessionWithHostData用于初始化Engine使用的Session数据,它会去检查我们传入的host对象是否实现了ITextTemplatingSessionHost,如有实现,则会将我们传入的Session带到内部去使用。在弄清原理后,我们就可以在Walkthrough: Creating a Custom Text Template Host介绍的自定义ITextTemplatingEngineHost实现类上,再添加实现ITextTemplatingSessionHost接口,然后在执行T4模板时,将需要的参数以Session的方式传给T4引擎使用:
  1. [Serializable]
  2. public class Parameter
  3. {
  4.     public string Name { get; set; }
  5. }
  6. class Program
  7. {
  8.     static void Main(string[] args)
  9.     {
  10.         Parameter parameter = new Parameter() { Name = "Name1" };
  11.         CustomTextTemplatingEngineHost host = new CustomTextTemplatingEngineHost();
  12.         host.TemplateFileValue = "test.tt";
  13.         Engine engine = new Engine();

  14.         string input = @"
  15. <#@ template debug=""false"" hostspecific=""false"" language=""C#"" #>
  16. <#@ output extension="".txt"" #>
  17. <#@ parameter name=""parameter1"" type=""T4ParameterSample.Parameter"" #>
  18. test output, paramter name value:<#= parameter1.Name #>

  19. ";

  20.         host.Session = new TextTemplatingSession();
  21.         host.Session.Add("parameter1", parameter);

  22.         string output = engine.ProcessTemplate(input, host);

  23.         Console.WriteLine(output);

  24.         foreach (CompilerError error in host.Errors)
  25.         {
  26.             Console.WriteLine(error.ToString());
  27.         }
  28.         Console.ReadLine();
  29.     }
  30. }
复制代码
    以上的实现是通过把参数值放在Session中传递到T4模板上下文中。同时我们也可以CallContext的方式来传递参数:
  1. CallContext.LogicalSetData("parameter1", parameter);
复制代码
    但是不管怎么样,是通过Session还是CallContext,我们的Host实例都是要实现ITextTemplatingSessionHost接口,并且为初始化Session属性。否则在调用this.Session.ContainsKey时就会出现空引用异常,因为它会优先去检查Session中是否有需要的参数值。
另外还有其它的办法,我们也可以达到类似的目的。比如:我们也可以定义自己的“声明”标识,然后通过自己解析这些”声明”,动态生成一些对象实例提供给T4模板使用,但是这种方法更为复杂,需要涉及动态对象生成和代码生成等技术。如有兴趣可参考:Walkthrough: Creating a Custom Directive Processor




收藏回复 只看该作者 道具 举报

高级模式
B Color Image Link Quote Code Smilies



QQ|小黑屋| 码途山海.智隐长卷 渝ICP备15002301号-2   渝公网安备50011202504426

GMT+8, 2025-5-18 02:14 , Processed in 0.043813 second(s), 23 queries .

©Copyright 程序人生!

©2012-2015重庆纽新

快速回复 返回顶部 返回列表