首页 > 解决方案 > 另一个文件中包含的 T4 缩进代码

问题描述

假设您有一个模板,您希望在其中包含来自另一个文件的代码。假设模板已命名Template.tt并具有以下内容:

<#@ template debug="false" hostspecific="true" language="C#" #>
<#@ assembly name="App" #>

namespace <#= Namespace #>
{
    public partial class <#= ClassName #>
    {
<#@ include file="Snippet.txt" #>
    }
}

包含类主体的Snippet.txt代码,尾随换行符:

public void Function() 
{
}

但是,如果您尝试运行模板,您会得到如下所示的代码:

namespace MyNamespace
{
    public partial class MyClass
    {
public void Function() 
{
}
    }
}

缩进它的一种方法是将包含文件中的每一行缩进所需的数量。然而,这不是一个令人满意的解决方案。有任何想法吗?

标签: c#formattingt4

解决方案


这个想法是在你的模板中使用函数PushIndent()PopIndent()这样的:

namespace <#= Namespace #>
{
    public partial class <#= ClassName #>
    { <# PushIndent("        "); #>

<#@ include file="Snippet.txt" #>
<# PopIndent(); #>

    }
}

除了这不起作用,因为生成的打印机代码使用该函数Write()打印输出,但是,Write()忽略缩进......

但!您实际上可以控制您的模板最终调用什么函数实现来打印输出。当 T4 为您的代码生成打印机类时,它会自动创建一个基类,其中包含 、 等函数Write()WriteLine()然后TransformText(),生成的模板设置为从该类继承,覆盖TransformText()以打印自己的文本。

这个想法是提供您自己的基类,该基类符合该基类的鸭接口,以便Write()使用缩进。T4 允许您这样做!例如,请参阅这篇博文供初学者参考。

要使用缩进,请注意它们仅用于新行。然后,更改Write()为以下内容:

public void Write(string textToAppend) 
{
     GenerationEnvironment.Append(textToAppend.Replace("\r\n", "\r\n" + currentIndent));
}

并从模板中的基类继承(例如,基类的名称是CodePrinterBase):

<#@ template debug="false" hostspecific="true" language="C#" inherits="CodePrinterBase" #>
<#@ assembly name="App" #>

namespace <#= Namespace #>
{
    public partial class <#= ClassName #>
    { <# PushIndent("        "); #>

<#@ include file="Snippet.txt" #>
<# PopIndent(); #>

    }
}

结果:

namespace MyNamespace
{
    public partial class MyClass
    {
        public void Function() 
        {
        }

    }
}

如果您还想删除片段后的新行,请删除该片段中尾随的新行。

需要明确的是,在这样的括号之后,因为在该代码运行PushIndent()需要插入一个新行。如果你把它放在括号下面并在它后面留下一个空行,如下所示,你会在输出中得到一个额外的空行:

{ 
<# PushIndent("        "); #>

<#@ include file="Snippet.txt" #>

运行它会给你:

namespace MyNamespace
{
    public partial class MyClass
    {

        public void Function() 
        {
        }

    }
}

这对我来说完美无缺!


推荐阅读