【问题标题】:How to disable #line directives being written to the T4 generation output file如何禁用正在写入 T4 生成输出文件的 #line 指令
【发布时间】:2011-12-14 18:48:41
【问题描述】:

我在生成 T4 代码时遇到了一个小问题。

我已将我的 T4 模板分解为单独的文件并将它们放置在不同的目录中,我这样做是为了让我的部分代码生成可以在多个项目中重复使用,例如模型生成、存储库生成和服务生成都包含一个核心 EntityGeneration.tt 文件。

不幸的是,当 TextTemplating 解析我的嵌套包含时,它会在其生成的 .cs 文件中构建一个长 #line 预处理器指令,将所有相对路径组合到最低级别的包含文件。

不幸的是,由于这条路径是由相对路径构成的,它最终会变得不必要地长,实际上它已经超过了最大路径长度(Windows 7)。

如果您感兴趣,这里是生成代码中的错误行:

#line 3 "C:\VS2010\AlbatrossTravelGroup\ASC\AlbatrossTravelGroup.ASC.BusinessRules\Services\Contracts\..\..\..\..\AlbatrossTravelGroup.BusinessRules\Services\Contracts\..\..\..\AlbatrossTravelGroup.Models\Repositories\Contracts\..\..\../AlbatrossTravelGroup.Common/CodeGeneration.tt"

我的问题是,如何禁用将这些指令写入生成的代码文件?如果做不到这一点,我怎样才能在不改变文件结构的情况下避免这个问题?

【问题讨论】:

  • 目前,作为临时解决方案,我创建了一个文件夹“CodeGeneration”,在该文件夹中创建了指向要包含的每个 T4 文件的符号链接。然后,它们不是通过相对路径包含其他 T4 文件的每个包含的 T4 文件,而是仅使用文件名。然后在我希望使用这些 T4 模板的最终位置,我使用“CodeGeneration”目录的相对路径。这导致路径长度更短,因为它使用更少的相对路径。如果有人想要完整的解释,我会在需要时发布答案:)
  • 我上面的临时解决方案坏了,不知道为什么 Visual Studio 开始无法解析文件。最后我不得不使用注册表来指定额外的 tt 包含目录,不太理想,但似乎是唯一可行的方法。
  • 您可以尝试类似here 提供的 VS 宏解决方案。

标签: c# path c-preprocessor t4


【解决方案1】:

Visual Studio 2012 添加了linePragmas="false" 模板指令:

<#@ template language="C#" linePragmas="false" #>

http://msdn.microsoft.com/en-us/library/gg586945(v=vs.110).aspx

仍然不确定如何在工作中遇到的 VS2010 中执行此操作。

【讨论】:

  • 这也适用于 VS 2019。它还禁用 #line hidden#line default 指令。
【解决方案2】:

我不确定这是否能解决您的问题。我对T4没有太多经验。也就是说,我正在使用它在我的项目中构建许多文件,并且我没有遇到您遇到的问题。

就我而言,我有一堆单独的 .tt 文件,它们在我的项目中呈现单独的文件。

我这样做的方式如下:我有一个 SaveOutput 方法(我相信是从 stackoverflow 的某个地方偷来的):

void SaveOutput(string outputFileName)
{
    if (!string.IsNullOrEmpty(outputFileName))
    {
        string templateDirectory = Path.GetDirectoryName(Host.TemplateFile);
        string outputFilePath = Path.Combine(templateDirectory, outputFileName);
        string output = this.GenerationEnvironment.ToString();
        File.WriteAllText(outputFilePath, output); 
    }

    this.GenerationEnvironment.Remove(0, this.GenerationEnvironment.Length);
}

所以在我的主 .tt 文件中,我有 用于各个文件的各种 .tt 文件。例如:

<#+
    public string GenerateInterfaceDataObject(sqlTable table)
    {
        string ifaceName = "I" + table.ObjectName;
        if (table.GenerateInterfaceObjectAsBase)
        {
            ifaceName += "Base";
        }
#>
using System;

namespace <#= InterfaceNamespace #>
{
    public interface <#= ifaceName #>
    {
<#+
        foreach(sqlColumn col in table.Columns)
        {
#>
        <#= GetColumnCSharpDataType(col) #> <#= col.FieldName #> { get; }
<#+
        }
#>
    }
}
<#+
        return RootPath + @"\AutoGenerated\" + ifaceName + ".cs";
    }
#>

然后,在我的主 .tt 类中,我只需进行如下调用:

string filePath = GenerateInterfaceDataObject(table);
SaveOutput(filePath);

不确定这种分解模板的方法是否能满足您的需求,但它适用于我,而且我还没有遇到任何问题。

我应该澄清一下,我的主 .tt 文件实际上并没有从自身生成任何东西。它本身不是模板。它只是加载每个模板并从其他模板生成文件。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2012-10-06
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多