T4模板和运行时参数

时间:2010-12-09 19:00:34

标签: c# visual-studio-2010 t4 template-engine

我正在VS 2010中构建一个插件,我陷入了T4代。 现在我已经实现了(比如MSDN建议的)一个自定义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来做到这一点,但我没弄明白如何将它传递给我的主机? 是否有更好的方法使用C#从.tt生成代码并在运行时传递参数?也许我走错了路。

7 个答案:

答案 0 :(得分: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 #>

老实说,主人不再需要了......

答案 1 :(得分:7)

如果要为VS构建加载项,则可能不需要自定义主机,而是可以通过其服务接口使用内置VS主机。

查看ITextTemplating作为核心服务API,您可以通过将DTE对象转换为IServiceProvider,然后调用GetService(typeof(STextTemplating))来获取

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

答案 2 :(得分:7)

向自定义主机添加并实施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;
            }
        }

答案 3 :(得分:4)

使用T4模板生成运行时

  1. 如果需要在运行时生成代码,请选择此方法。例如,您想使用Selenium生成页面对象。

    enter image description here

  2. 在解决方案中创建一个文件夹,将其命名为Templates(的名称为 T4模板)。

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

  4. 如下所示添加代码,顶部由Visual Studio插入...

  5. Add Code

    您可以看到我们要传递Namespace和ClassName(这些是上面看到的Model.NameSpaceName和Model.ClassName标记。

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

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

    Partial File Name

    但是在类中没有将MyNodeNamePartial命名为MyNodeName,如下所示:

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

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

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

    模型类包含ClassName和NameSpaceName以及您要“注入”模板的任何其他内容。

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

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

答案 4 :(得分: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();

答案 5 :(得分:0)

想出来。对于有兴趣的人,请看以下内容:

http://www.olegsych.com/2009/09/t4-preprocessed-text-templates/

答案 6 :(得分:0)

我尝试了所有答案以使其起作用,但没有一个适合我的情况。最终,我在模板中添加了以下内容...

<#@ assembly name="System.CodeDom" #>

..然后有效