如何从基类更改T4模板的输出?

时间:2014-10-12 23:46:35

标签: visual-studio-2010 visual-studio-2012 t4

我想创建一个工具作为T4模板的基类,以便在Visual Studio .NET中的设计时生成代码。我希望我的TextTransformation派生基类能够最终说明输出到生成文件的内容。问题是使用.NET反射器我找不到一个方法,我可以覆盖(或声明为新)或任何事件,以便在它被T4框架使用之前更改GenerationEnvironment属性的内容。

以下是基类的示例:

public class MyTool
    : TextTransformation
{
    public override void Initialize()
    {
        // Initialize My Tool

        base.Initialize();
    }

    // Override the text that is generated from the T4 template and modify it 
    // (strip out some well known .NET attributes) here.

}

它将继承自T4模板,如下所示:

<#@ template debug="false" hostspecific="true" language="C#" inherits="MyTool" #>
<#@ assembly name="System.Core" #>
<#@ assembly name="MyTool.dll" #>
<#@ assembly name="Microsoft.VisualStudio.TextTemplating.10.0" #>
<#@ import namespace="System.Linq" #>
<#@ import namespace="System.Text" #>
<#@ import namespace="System.Collections.Generic" #>
<#@ import namespace="MyTool" #>
<#@ output extension=".cs" #>

[Ender]
public interface INinjaEnder
{
    INinja Build();
}

[Required]
public interface INinjaNamed<TRemainder>
{
    TRemainder Named(string name);
}

public interface INinjaCostume<TRemainder>
{
    TRemainder WithCostume(Costume costume);
}

我可以在MyTool中的Initialize()方法或Dispose()方法(覆盖时)中查找断点,但似乎没有任何东西可用于修改输出。我正在考虑的一些选择:

  1. 使用Dispose()方法创建一个单独的文件以输出更改的内容,并完全忽略T4模板的输出。遗憾的是,在Dispose()方法中生成具有相同名称的文件不起作用,因为它会被原始文本覆盖。
  2. 强制最终用户在每个模板的末尾添加一个方法调用,这样我就可以在合适的时间运行我需要的东西。
  3. 覆盖WriteLine()和/或Write()方法(使用new)并使用它们去除最终文件中我不想要的文本。这可能需要在GenerationEnvironment的输出上进行RegEx匹配,这样我就可以看到代码是否在那里并且在剥离之前完全生成。
  4. 我还想过将StringBuilder子类化为覆盖ToString()方法(GenerationEnvironment返回一个StringBuilder),但StringBuilder类是密封的。

    我应该提一下,我的目标是Visual Studio 2010,2012和2013的所有版本(包括快速版)。我注意到2010年到2012年T4有一些很大的差异,所以我需要拿出来适用于两种环境的解决方案。

    某些情境

    我沿着这条道路前进的理由是:

    1. T4受快速版本,自定义工具(IVsSingleFileGenerator)支持,而设计人员则不支持。我的目标受众(开源开发人员)的很大一部分可能会使用快速版本。
    2. 我希望用户将输入指定为代码(通过T4模板的接口和属性),因此他们没有陡峭的学习曲线来使用我的工具,必须输入更抽象的东西,如XML,图表或设计师。
    3. 我不希望用户必须设置对我的DLL的引用(因此必须使用他们的代码发送DLL)才能使用我的工具。使用T4,我可以在使用它们完成生成器后从最终代码中删除属性,因此只有我的工具需要引用属性。
    4. T4通过基类的属性注入支持依赖注入,因此我的用户将能够为我的工具提供自己的扩展。
    5. 我可以支持VB和C#T4模板,而不会创建太多的重复代码(因为大部分代码都在我的DLL中)。
    6. 但是,如果有比T4基类更好的选择,我会接受架构建议。

0 个答案:

没有答案