C# 使用T4模板中与模板存在于同一项目中的类型

C# 使用T4模板中与模板存在于同一项目中的类型,c#,.net,vb.net,code-generation,t4,C#,.net,Vb.net,Code Generation,T4,我正在开发我的第一个T4代码生成工具,将一些存储过程帮助程序代码添加到我的项目中。我创建了自定义类型(例如StoredProcedure和StoredProcedureParameter),以帮助生成代码,并在代码中包含程序集和命名空间引用: <#@ template debug="false" hostspecific="false" language="VB" #> <#@ output extension=".generated.vb" #> <#@ asse

我正在开发我的第一个T4代码生成工具,将一些存储过程帮助程序代码添加到我的项目中。我创建了自定义类型(例如
StoredProcedure
StoredProcedureParameter
),以帮助生成代码,并在代码中包含程序集和命名空间引用:

<#@ template debug="false" hostspecific="false" language="VB" #>
<#@ output extension=".generated.vb" #>
<#@ assembly name="$(TargetPath)" #>
<#@ import namespace="StoredProcCodeGenerator" #>

这允许我在T4模板代码中使用我的自定义类型。但是,由于我的自定义类型与T4模板代码存在于同一个项目中,因此在运行模板代码后,如果不重新启动Visual Studio,我将无法重新编译我的项目。这不是很有趣

我读到一篇文章,其中提到了使用T4工具箱解决这个问题,但它不起作用。要么我执行的
VolatileAssembly
指令错误,要么T4工具箱根本没有安装。我不确定工具箱是否安装正确(我在Win XP上使用VS 2010)


有哪些方法可以解决此问题?

您需要删除以前的
程序集
引用,然后添加
VolatileAssembly
引用。如果不先删除常规的
程序集
引用,则在添加
volatileas时会出现一个错误,即它已经被添加embly
参考

<#@ template debug="false" hostspecific="false" language="VB" #>
<#@ output extension=".generated.vb" #>



现在,您可以继续构建您的项目,并在T4模板中使用该项目中定义的类型。

希望这会有所帮助,它显示了使用volatileAssembly的一个用例,我一点运气都没有,但我认为它可能会有所帮助:

// <autogenerated/>
// Last generated <#= DateTime.Now #>
<#@ template language="C#" hostspecific="true"#>

<#@ assembly name="System" #>

<#@ VolatileAssembly processor="T4Toolbox.VolatileAssemblyProcessor" name="bin\debug\FrameworkWpf.dll" #>
<#@ VolatileAssembly processor="T4Toolbox.VolatileAssemblyProcessor" name="bin\debug\FrameworkTestToolkit.dll" #>
<#@ VolatileAssembly processor="T4Toolbox.VolatileAssemblyProcessor" name="bin\debug\WpfAppTemplate.exe" #>

<#@ output extension=".cs" #>

<#@ import namespace="System" #>
<#@ import namespace="FrameworkTestToolkit" #>

namespace WpfAppTemplateTest {
 using System;
 using System.Reflection;
<# 
    // Add new types into the below array:
    Type[] types = new Type[] { 
 typeof(FrameworkWpf.SafeEvent),
 typeof(FrameworkWpf.Mvvm.ControllerBase),
 typeof(FrameworkTestToolkit.PrivateAccessorGeneratorTestClass),
 typeof(WpfAppTemplate.PostController),
 typeof(WpfAppTemplate.ShellController),
 };


 // Do not modify this code
 foreach (Type type in types) {
 PrivateAccessorGenerator builder = new PrivateAccessorGenerator(type, WriteLine, Error, Warning);
 builder.Generate();
 }
#>
}

/

您还可以使用以下方法浏览代码:



我不明白。在VS2010中,我一直使用T4模板,包括使用与模板在同一项目中的类型,它工作得很好,每当我保存时都会重新运行模板——正如我所期望的那样。@Kirk我没有意识到在添加
之前我必须删除
,有人可以编辑标题说template而不是tempat吗e快开始了?@Maslow-Ha!太棒了。我可能已经开始写标题50次了,但从来没有注意到。谢谢!如果你都没有,会发生什么?(我既没有“assembly”也没有“VolatileAssembly”,我总是可以访问包含.tt文件的项目中的类。)@Kirk这很有趣。如果我不包含程序集引用,我会得到一个错误,它找不到我的自定义类型。例如,我在.tt文件中使用了一个
StoreProcedure
类型。如果我不引用我的程序集,它将无法找到
StoredProcedure
类型。Kirk,你可能正在使用VS2008吗?20年08,我们也从项目引用中引入了本地类型作为stadard搜索。我们在2010年删除了它,以便您的T4世界与您实际构建的内容隔离。我们这样做是为了在模板中使用.Net 4.0时支持针对.Net 2.0或3.5项目。但这只是将RootNamespace作为字符串文本。您如何使用它作为指示?
// <autogenerated/>
// Last generated <#= DateTime.Now #>
<#@ template language="C#" hostspecific="true"#>

<#@ assembly name="System" #>

<#@ VolatileAssembly processor="T4Toolbox.VolatileAssemblyProcessor" name="bin\debug\FrameworkWpf.dll" #>
<#@ VolatileAssembly processor="T4Toolbox.VolatileAssemblyProcessor" name="bin\debug\FrameworkTestToolkit.dll" #>
<#@ VolatileAssembly processor="T4Toolbox.VolatileAssemblyProcessor" name="bin\debug\WpfAppTemplate.exe" #>

<#@ output extension=".cs" #>

<#@ import namespace="System" #>
<#@ import namespace="FrameworkTestToolkit" #>

namespace WpfAppTemplateTest {
 using System;
 using System.Reflection;
<# 
    // Add new types into the below array:
    Type[] types = new Type[] { 
 typeof(FrameworkWpf.SafeEvent),
 typeof(FrameworkWpf.Mvvm.ControllerBase),
 typeof(FrameworkTestToolkit.PrivateAccessorGeneratorTestClass),
 typeof(WpfAppTemplate.PostController),
 typeof(WpfAppTemplate.ShellController),
 };


 // Do not modify this code
 foreach (Type type in types) {
 PrivateAccessorGenerator builder = new PrivateAccessorGenerator(type, WriteLine, Error, Warning);
 builder.Generate();
 }
#>
}
        <#@ template language="C#" hostspecific="True" debug="True" #>
    <#@ output extension="cs" #>
    <#@ assembly name="System.Core" #>
    <#@ assembly name="System.Xml" #>
    <#@ assembly name="Microsoft.VisualStudio.Shell.Interop.8.0" #>
    <#@ assembly name="EnvDTE" #>
    <#@ assembly name="EnvDTE80" #>
    <#@ assembly name="VSLangProj" #>
    <#@ import namespace="System.Collections.Generic" #>
    <#@ import namespace="System.IO" #>
    <#@ import namespace="System.Linq" #>
    <#@ import namespace="System.Text" #>
    <#@ import namespace="System.Text.RegularExpressions" #>
    <#@ import namespace="System.Xml" #>
    <#@ import namespace="Microsoft.VisualStudio.Shell.Interop" #>
    <#@ import namespace="EnvDTE" #>
    <#@ import namespace="EnvDTE80" #>
    <#@ import namespace="Microsoft.VisualStudio.TextTemplating" #><#
    var serviceProvider = Host as IServiceProvider;
        if (serviceProvider != null) {
            Dte = serviceProvider.GetService(typeof(SDTE)) as DTE;
        }

        // Fail if we couldn't get the DTE. This can happen when trying to run in TextTransform.exe
        if (Dte == null) {
            throw new Exception("T4Generator can only execute through the Visual Studio host");
        }

        Project = GetProjectContainingT4File(Dte);

        if (Project == null) {
            Error("Could not find the VS Project containing the T4 file.");
            return"XX";
        }

        AppRoot = Path.GetDirectoryName(Project.FullName) + '\\';
        RootNamespace = Project.Properties.Item("RootNamespace").Value.ToString();

        Console.WriteLine("Starting processing");
        ProcessFileCodeModel(Project);
    #>