13

我想在我的 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 但没有任何效果。

有任何想法吗 ?

4

5 回答 5

17

这是完整的解决方案:

  1. 将类分离到另一个项目中

  2. 通过 TT 包含对这些类的引用

    <#@ assembly name="$(TargetDir)MyOwnLibraryProject.dll" #>
    <#@ import namespace="MyOwnNamespace" #>
    
  3. 不要忘记将此库的引用包含在您的 TT 项目中

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

  5. 魔法出现!!!

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

于 2014-08-01T11:24:09.043 回答
8

如果我对您的理解正确,那么您正在尝试重用一个类作为模板生成的一部分。

该类需要在 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 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"#>
于 2014-07-28T08:14:00.023 回答
3

我自己也有同样的问题——我的解决方案就像@Tehseen 的一样,除了我会提供一个带有解释的实际解决方案:)

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

这是我的解决方案:

我的“入口点” MyScript.ttT4 脚本如下所示:

<#@ 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文件。
  • 包含的文件不能作为它自己的 T4 文件执行,因为缺少我理解的<#@ template #>指令<#@ output #>必须放在文件的开头。
    • 当然,大多数包含*.ttinclude的文件无论如何都不能自己执行。
于 2019-11-08T04:09:35.080 回答
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 文件的行。

于 2014-07-26T09:39:20.453 回答
-1

在您的导入语句之后添加它应该可以工作:

<#
ClassDefinition cd = new ClassDefinition();
#>
于 2016-10-28T10:35:38.287 回答