简体   繁体   English

自定义T4预处理模板

[英]Customizing a T4 preprocessed template

What I'm trying to do 我想做什么

I'm trying to use T4 to create a mail message template. 我正在尝试使用T4创建邮件消息模板。

I am using a preprocessed template , which, if I understoo correctly, is what I have to do if I want to generate the message at run time without introducing a dependency on the Microsoft.VisualStudio.TextTemplating assembly. 我正在使用一个预处理模板 ,如果我正确地说,如果我想在运行时生成消息而不引入对Microsoft.VisualStudio.TextTemplating程序集的依赖,那么我就必须这样做。

Since I want to pass some data to my template, I added parameters to it: 由于我想将一些数据传递给我的模板,我添加了参数:

<#@ template language="C#" #>
<#@ parameter name="Param1" type="System.String" #>
<#@ parameter name="Param2" type="System.    
Lorem <#= Param1 #> dolor <#= Param2 #>

Then I can generate the message passing arguments like this: 然后我可以像这样生成传递参数的消息:

static void Main(string[] args) {
    var template = new LoremIpsum();
    template.Session = new Dictionary<string, object>() { 
        {"Param1", "ipsum"},
        {"Param2", "sit amet"},
    };
    template.Initialize();
    string text = template.TransformText();
}

What is the problem 问题是什么

Since I need to generate several of these classes, I would like them all to have a common method to send a mail, something like this: 由于我需要生成其中几个类,我希望它们都有一个通用的方法来发送邮件,如下所示:

public void SendMail(string to, IDictionary<string, object> parameters)

or, even better: 或者,甚至更好:

public void SendMail(string to, string Param1, string Param2)

Since the generated classes are partial, it is possible to add methods to them adding another partial class declaration, but this would mean that I would have to repeat the (more or less) same code for all the generated classes. 由于生成的类是部分的,因此可以向它们添加添加另一个部分类声明的方法,但这意味着我必须为所有生成的类重复(或多或少)相同的代码。

What I tried so far 到目前为止我尝试了什么

I tried creating a base class, but if I try to do this: 我尝试创建一个基类,但如果我尝试这样做:

<#@ template language="C#" inherits="MailTemplateBase" #>

then the generated code breaks, as the generated class was relying on the LoremIpsumBase base class which defined some helper methods (and I really see no point in having each generated class inherit from an almost identical but distinct base class). 然后生成的代码中断,因为生成的类依赖于定义了一些辅助方法的LoremIpsumBase基类(我真的认为每个生成的类继承自几乎相同但不同的基类没有意义)。

Questions 问题

  1. How can I have a base class for my templates? 如何为模板创建基类?
  2. How can I generate a method that accepts the same parameters as those declared in the template? 如何生成一个接受与模板中声明的参数相同的参数的方法?

I think you need to create an empty template, copy the created class and use it as your base class. 我认为你需要创建一个空模板,复制创建的类并将其用作基类。 You can then extend it with whatever properties you need. 然后,您可以使用您需要的任何属性扩展它。 (you don't need to keep the empty template once you've copied the code) (复制代码后,您不需要保留空模板)

For what it's worth I think what you are trying to do worked out of the box in VS 2010 RTM, but VS2010 SP1 changed the behaviour so that you can subclass templates themselves. 值得一提的是,我认为你想要做的是在VS 2010 RTM中开箱即用,但是VS2010 SP1改变了行为,这样你就可以自己对模板进行子类化。 Check out this connect issue for more info. 有关详细信息,请查看此连接问题

EDIT: 编辑:

As far as putting an email method on the base goes, I probably wouldn't do it that way. 至于在基础上放置一个电子邮件方法,我可能不会这样做。 You might want to think about exposing some sort of templating service that has the various methods on it that you need, eg: 您可能想要考虑暴露某种模板服务,该服务具有您需要的各种方法,例如:

public class TemplatingService : ITemplatingService
{
    public string GenerateReminderMessage(string to, string name)
    {
        // Construct the template, passing in the parameters into the session as required
        ...
        // Return the results of the template transformation
    }
}

That way you're abstracted away from the actual T4 implementation so if something does break somewhere down the line you only have to fix it in one class. 这样你就可以从实际的T4实现中抽象出来,所以如果某些东西确实在某个地方破坏了你只需要在一个类中修复它。

And expose a mail service that uses the templating service to generate the mail contents: 并公开使用模板服务生成邮件内容的邮件服务:

public class MailService : IMailService
{
    public void SendReminderEmail(string to, string name)
    {
        var message = this.TemplatingService.GenerateReminderMessage(to, name);
        this.MailerService.SendEmail(to, message);
    }
}

Note that the MailerService would just a simple wrapper around the .NET mail code, but it would allow you to unit test the MailService in isolation. 请注意,MailerService只是一个围绕.NET邮件代码的简单包装器,但它允许您单独测试MailService。

There are probably more ways you could abstract it out, but that would be a start. 可能有更多方法可以将其抽象出来,但这将是一个开始。

Hope that helps. 希望有所帮助。

It sounds like you assumption is that the constructor injection is the only way to inject the data to a class. 听起来你假设构造函数注入是将数据注入类的唯一方法。 I guess however that metod/property injections are better options in this scenario. 我想在这种情况下,metod / property注入是更好的选择。

I don't have the compiler at hand and can't verify it for sure but it seems it may work. 我手头没有编译器,无法确认它,但它似乎可以工作。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM