从T4模板中调用同一项目中的类

8

我正在尝试创建一些CRUD类的脚手架,并希望使用T4来辅助构建这些类。我刚刚开始,遇到了一个问题,就是在调用同一项目中存在的类时出现了问题。例如:

<#@ import namespace="System.Collections.Generic" #>
<#@ template    language="C#"   #>
<#@ output      extension=".cs" #>
<#@ include file="T4Toolbox.tt" #>

using System;
using System.Data;
using System.Data.Linq;
using System.Collections.Generic;

namespace TTFileGenerator
{
<#var entityName = "TEST";#>
    public class <#=entityName#>
    {
    <#
            MyClass myClass = new MyClass();
            List<string> something = myClass.GetSomething()
            ...
    #>
    }
}

错误信息:

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

这是同一项目中的公共类。我可以从其他类中访问它,但不能从 T4 文件中访问。我还是一个 T4 新手。希望能给予任何指导。
3个回答

7
你想要做的事情不会很简单。为了让T4使用一个类(如MyClass),生成器必须引用包含该类的程序集或完全在T4中定义的类(这就是EF代码生成器所做的)。此外,你可能正在使用设计时T4(让IDE进行生成)。设计时T4生成器将持有dll的引用,因此你将无法再次构建项目。你实际上必须关闭Visual Studio并重新启动它。<叹气>
如果你决定采取第一种方法——我非常赞同——你需要将代码分成两个程序集(实际上是三个)。一个包含你编写的代码,例如MyClass。第二个用于生成的代码。
创建第三个程序集(命令行项目)并在其中使用运行时T4。这个项目可以引用你的第一个程序集(带有MyClass),并且可以对它进行任何你想做的事情,包括你在这里展示的代码!将代码生成到第二个程序集中。
在第一个项目的项目设置中,将第三个项目的命令行工具作为后生成事件调用。这也可以是第二个项目的预生成事件。
我用这种方法创建了几个成功的面向方面编程(AOP)解决方案。遗憾的是,这可能不是你所希望的答案。
如果你真的很勇敢,你可以让命令行工具生成回原始项目。这将要求你编译两次。我目前无法推荐这样做。

感谢非常详细的回答,Phillip。我怀疑这就是为什么我在其他示例中看到类似的代码可以工作,而从未真正解释过的原因。我将尝试拆分应用程序,以便执行工作的TT可以引用托管要调用的方法的程序集。 - user3219570
1
VS2012/VS2013应该在不同的应用程序域/影子复制中加载程序集,这样就不会对dll文件保持锁定状态。另一种方法是使用Roslyn来加载语法树,我看到了一些其他帖子使用IDE API(不知何故)。个人而言,我更喜欢在T4文件中定义模型。 - Just another metaprogrammer
@FuleSnabel,很高兴知道这个。澄清一下,我上次尝试从Design-Time T4生成器引用程序集是在VS2010中;那时,它锁定了程序集。 - Phillip Scott Givens
那是一个漫长的努力。 - Worthy7

4

我觉得我应该添加一些代码来帮助其他人,尽管Phillip已经说得很好了。

我必须将我想要调用的类拆分到另一个程序集中,并使用相对路径进行程序集引用。我没有看到任何锁定(VS 2012)...如果您在转换T4模板之前进行任何更改,请记得构建此程序集:

//Reference to another project (for testing, it lives in the debug folder)
<#@ assembly name="$(SolutionDir)\MyAssembly\bin\x86\Debug\MyAssembly.dll"#>

<#  
    var helper = new Utilities.MyHelperClass();
#>

<#
     var something = helper.GetSomething(param1, param2);
#>

可以确认这在VS2017下很好地工作。在我的情况下,我将新项目设置为使用“所有CPU”进行构建。 - Contango

0

您可以从构建中排除 cs 文件,并使用 include 语句将其包含进来。这样做看起来会很丑,因为类会附加到模板上,但对于简单的类来说,这种方法是可行的。


1
提供更多细节。 - Pradeep Kumar

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接