T4 - TT - 在TT文件中使用自定义类

时间:2014-07-25 14:10:48

标签: c# t4 css texttemplate

我想在我的TT中的CS文件中使用我自己的类定义。

示例:

public class ClassDefinition
{
    public string NameSpace { get; set; }
    public string Name { get; set; }
    public string Protection { get; set; }

    List<ClassProperty> Properties { get; set; }
}

我的TT看起来像:

<#@ template debug="true" hostspecific="true" language="C#" #>
<#@ output extension=".cs" #>

<#@ assembly name="System" #>
<#@ assembly name="System.Core" #>
<#@ assembly name="System.Xml"#>

<#@ import namespace="System.Xml" #>
<#@ import namespace="System.Linq" #>
<#@ import namespace="System.Text" #>
<#@ import namespace="System.Collections.Generic" #>
<#@ import namespace="System.IO" #>

<#@ include file="$(ProjectDir)ClassDefinition.cs" #>

<#

// Read the model file
XmlDocument doc = new System.Xml.XmlDocument();
doc.Load(this.Host.ResolvePath("GeneratedXmlFile.xml"));

IList<XmlNode> nodeList = new List<XmlNode>();
foreach (XmlNode node in doc.DocumentElement)
{
    switch(node.Name)
    {
        case "Model": 
        {
            ClassDefinition classDefinition = new ClassDefinition();

但是我有这样的错误信息:

  

编译转换:找不到类型或命名空间名称“ClassDefinition”(您是否缺少using指令或程序集引用?)

我在网上查了一下并试图: - 使用包括 - 使用组装 - 使用USING 但没有任何作用。

有什么想法吗?

5 个答案:

答案 0 :(得分:14)

以下是完整的解决方案:

1)将类分成另一个项目 2)通过TT

包括对这些类的引用
<#@ assembly name="$(TargetDir)MyOwnLibraryProject.dll" #>
<#@ import namespace="MyOwnNamespace" #>

3)不要忘记在TT项目中包含此库的参考

4)您必须将MyOwnLibraryProject.dll复制到TT解决方案的BIN \ DEBUG文件夹中

5)神奇的出现!!!

每次更改DLL时都不要忘记将新版本放入文件夹:) 或者只是将Library项目输出配置为与TT项目输出相同。 我想感谢大家提供指导和想法。

答案 1 :(得分:5)

如果我理解正确,您就会尝试重复使用某个类作为模板生成的一部分。

该类本身需要在tt文件中,构建操作设置为none,自定义工具 - 什么都没有。我所拥有的是模板管理器类,顶部有以下内容:

<#@ template language="C#" #>
<#@ assembly name="System.Core" #>
<#@ import namespace="System.Linq" #>
<#@ import namespace="System.Text" #>
<#@ import namespace="System.Collections.Generic" #>
<#@ import namespace="System.Diagnostics" #>

<#+
public class TemplateManager
{

然后在我使用的其他t4模板中:

<#@ include file="TemplateManager.tt"#>

然后

List<Values> values = TemplateManager.PrepareVariables(code, container, itemCollection.OfType<EntityType>())

在您的情况下,ClassDefinition.tt文件将包含:

<#@ template language="C#" #>
<#@ assembly name="System.Core" #>
<#@ import namespace="System.Linq" #>
<#@ import namespace="System.Text" #>
<#@ import namespace="System.Collections.Generic" #>
<#@ import namespace="System.Diagnostics" #>

<#+
public class ClassDefinition
{
    public string NameSpace { get; set; }
    public string Name { get; set; }
    public string Protection { get; set; }

    List<ClassProperty> Properties { get; set; }
}
#>

然后你可以加入

<#@ include file="ClassDefinition.tt"#>

答案 2 :(得分:1)

使用以下命令将C#文件包含在T4模板中:

<#@ include file="$(ProjectDir)ClassDefinition.cs" #>

将文本添加到T4模板的输出中。它不编译该类。

您在T4模板中设置了debug = true,以便在查看%TEMP%目录时可以看到T4生成的内容。运行T4模板时,您应该看到TEMP目录中生成的.cs文件。在这个文件中你将有类似的东西:

 this.Write("public class ClassDefinition\r\n{\r\n    public string NameSpace { get; set; }\r\n    p" +
       "ublic string Name { get; set; }\r\n    public string Protection { get; set; }\r\n\r\n " +
       "  List<ClassProperty> Properties { get; set; }\r\n}");

所以C#类发生的一切就是它将在生成的T4输出中写出来。

您可能想要做的是在项目中包含ClassDefinition.cs文件,以便将其编译为项目的一部分。然后,您可以引用包含ClassDefinition类的程序集。因此,如果您的项目输出是MyLibrary.dll,其中包含已编译的ClassDefinition.cs,那么您应该可以使用:

<#@ assembly name="$(SolutionDir)$(OutDir)MyLibrary.dll" #>

应删除包含ClassDefinition.cs文件的行。

答案 3 :(得分:0)

我自己也遇到了同样的问题-我的解决方案类似于@Tehseen的解决方案,除了我将提供带有解释的实际解决方案:)

将任意C#包含到T4文件中的技巧(您希望导入的C#由T4使用,而不是简单地包含为原始文本)是隐藏* .cs文件中T4阻塞的部分-像using指令之类的东西,并确保类型在<#+(而不是<#)块中声明。

这是我的解决方法:

我的“入口点” MyScript.tt T4脚本如下:

<#@ template debug="true" hostspecific="false" language="C#" #>
<#@ assembly name="System.Core" #>
<#@ import namespace="System.Linq" #>
<#@ import namespace="System.Text" #>
<#@ import namespace="System.Text.RegularExpressions" #>
<#@ import namespace="System.Collections.Generic" #>
<#@ include file="IncludedCSFile.cs" #>
<#@ output extension=".cs" #>
<#

MyClass foo = new MyClass(); // This is using a type from `IncludedCSFile.cs` in the T4 script.

#>

Hello, <#= foo.Name #>

我的IncludedCSFile.cs如下:

// <#+ /*

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text.RegularExpressions;

namespace MyNamespace
{

// */

    public class MyClass
    {
        // etc...
    }
}
// #>

说明:

// <#+ /*
  • 最初的//会阻止主C#解析器(来自项目)看到T4 <#+分隔符,这会导致项目语法错误。
  • <#+ ,由T4解析器解析,并导致文件中的C#被解释为T4脚本可以使用的代码。
  • 后面的/*开始一个新注释,该注释使T4的C#解析器忽略using...语句并打开namespace MyNamespace行,否则将导致T4语法错误。
    • 这是因为T4要求将using语句表示为<#@ import namespace="" #>指令。
// */
  • 这是第一个<#+后面的开始块注释的分隔符。
  • //在项目C#编译器(看不到*/)中隐藏了/*,而T4的C#编译器将看到它,因为//是被上一个/*覆盖。
    • 之所以可行,是因为在C#中,块注释将“注释掉”其他注释(如果有意义的话!)。
// #>
  • 最后,T4在EOF之前需要一个T4块终止符,因此我们使用相同的前导//技巧将其隐藏在C#中,而T4仍然可以看到它。

缺点:

此方法有一些缺点:

  • 前导//将呈现到最终输出文件中。
    • 我认为这无法缓解。
    • 如果您知道解决方案,请编辑此答案或在评论回复中告诉我!
  • 包含的T4文件无法声明其自己的名称空间导入。
    • 尽管这对于小型T4脚本来说不是问题,但确保将它们全部添加到入口点T4脚本中也不成问题。
    • 另一种解决方法是创建一个实际的*.ttinclude文件,该文件仅具有必要的<#@ import namespace="" #>指令,然后包含*.cs文件。
  • 由于缺少<#@ template #><#@ output #>指令,因此无法将包含的文件作为其自己的T4文件执行,据我了解,这些指令必须放在文件的开头。
    • 已授予许可,大多数包含的*.ttinclude文件仍然无法自行执行。

答案 4 :(得分:-1)

在导入语句应该起作用后添加:

<#
ClassDefinition cd = new ClassDefinition();
#>