2010-12-09 90 views
8

我在VS 2010中构建了一个插件,我陷入了T4代。 现在我已经实现(如MSDN建议)自定义T4主机生成我的T4结果我用它这样:T4模板和运行时参数

 const string content = @"c:\Simple.tt"; 
     var engine = new Engine(); 
     var host = new MyTemplateHost();    
     var result = engine.ProcessTemplate(File.ReadAllText(content), host); 
     foreach (CompilerError error in host.Errors) 
     { 
      Console.WriteLine(error.ErrorText); 
     } 

这工作,直到我传递参数的模板。只要我在.tt文件中创建一个参数,主机就会发出警告,说它不知道如何解决它。 我看到你可以使用TemplateSession来做到这一点,但我没有弄清楚如何将它传递给我的主机? 有没有更好的方式从.tt使用C#生成代码并在运行时传递参数?也许我走错了路。

回答

12

在Visual Studio 2010中,T4模板引擎已经根本改变了。 现在你可以直接运行一个模板文件并传给它任何参数你想要的类型。

 var template = Activator.CreateInstance<SimpleTemplate>(); 
     var session = new TextTemplatingSession(); 
     session["namespacename"] = "MyNamespace"; 
     session["classname"] = "MyClass"; 
     var properties = new List<CustomProperty> 
     { 
      new CustomProperty{ Name = "FirstProperty", ValueType = typeof(Int32) } 
     }; 
     session["properties"] = properties; 
     template.Session = session; 
     template.Initialize(); 

本声明将处理以下模板:

<#@ template language="C#" debug="true" #> 
<#@ output extension=".cs" #> 
<#@ assembly name="System.dll" #> 
<#@ import namespace="System" #> 
<#@ import namespace="System.Collections.Generic" #> 
<#@ import namespace="SampleDomain.Entities" #> 
<#@ parameter name="namespacename" type="System.String" #> 
<#@ parameter name="classname" type="System.String" #> 
<#@ parameter name="properties" type="System.Collections.Generic.List<CustomProperty>" #> 

using System; 
using System.Collections.Generic; 
using SampleDomain.Entities; 

namespace <#= this.namespacename #> 
{ 
public class <#= this.classname #> 

所以诚实是不是真的需要主机了...

+0

这代码似乎使用preprocesed模板(如果我理解你的类型SimpleTemplate承担。看我为如何去使用这个内置的VS主机。 – GarethJ 2011-01-13 02:42:52

+0

非常有帮助谢谢回答。在2012年,也适用此呼叫后`Initialize()`你也可以通过检查`template.Errors.HasErrors`来查看类型是否正确传递:) – 2013-11-24 12:22:39

7

如果你正在建立一个附加在VS,你可能不需要自定义主机,但可以通过其服务接口使用内置的VS主机。

退房ITextTemplating为核心服务的API,它可以完整投放DTE对象到的IServiceProvider,然后调用GetService的(typeof运算(STextTemplating))

要传递的参数得到,你就可以边抛弃的ITextTemplating对象到ITextTemplatingSessionHost并将Session属性设置为ITextTemplatingSession的实现。会话本质上只是一个可序列化的属性包。有一个简单的提供为TextTemplatingSession

+0

谢谢,我明天必须在办公室给它一个镜头。 – Raffaeu 2011-01-14 02:23:58

6

添加和落实ITextTemplatingSessionHost到自定义的主机。只是实施ITextTemplatingEngineHost不会给你会议支持。

[Serializable()] 
    public class CustomCmdLineHost : ITextTemplatingEngineHost,ITextTemplatingSessionHost 
    { 

     ITextTemplatingSession session = new TextTemplatingSession(); 

     public ITextTemplatingSession CreateSession() 
     { 
      return session; 
     } 

     public ITextTemplatingSession Session 
     { 
      get 
      { 
       return session; 
      } 
      set 
      { 
       session = value; 
      } 
     } 
1

看看MSDN Reference(“在构造函数中传递参数”部分)。

总结:

与TT文件同名创建一个部分类。

partial class MyWebPage 
{ 
    private MyData m_data; 
    public MyWebPage(MyData data) { this.m_data = data; }} 
} 

然后,只需将您的参数在类

MyWebPage page = new MyWebPage(data); 
String pageContent = page.TransformText(); 
4

使用T4模板的运行时生成

  1. 的构造函数,如果你需要生成你选择这个方法代码在运行时。例如,你想用Selenium生成一个页面对象。

    enter image description here

  2. 在解决方案中创建一个文件夹,命名为模板(好名字 T4模板)。

  3. 接下来添加一个T4类型的新项目,然后选择 运行时文本模板....我们将模板MyNodeName.tt命名为上图中的模板。

  4. 添加您的代码如下所示,上部是由Visual Studio插入...

Add Code

你可以看到,我们希望在命名空间和类名传递(这些是的Model.NameSpaceName和Model.ClassName标记上面看到的。

棘手的部分是学习如何在参数传递...

在文件名中创建名称为partial的新CS类。

Partial File Name

但在类不要将其命名MyNodeNamePartial命名MyNodeName这样的:

public partial class MyNodeName 
    { 
     public MyNodeNameModel Model { get; set; } 
    } 

这是相同的名称TT文件。 (MyNodeName),它创建它自己的部分类。但是现在我们看到有一个名为这类类型的模型值..

public class MyNodeNameModel 
    { 
     public MyNodeNameModel() 
     { 
      ClassName = "Test"; 
     } 
     public string ClassName { get; set; } 
     public string NameSpaceName { get; set; } 
    } 

模型类包含类名和NameSpaceName和其他任何你想“注入”到模板。

该工作的关键如图所示, 是使用运行时文本模板!如果您使用文本模板,无论您做什么,都会看到类似“模型未找到”或其他模糊问题的错误。

调试提示: “模型无法找到”是T4代代码,告诉您在您的部分类中使用名为MODEL的变量,它无法找到它!检查你的部分类型和模型类型,以确保它们在相同的命名空间中,正如在该文件夹中创建的任何其他普通类名称空间一样。