你能在T4模板中使用全局变量吗?

4

我如何在TT文件中使用全局变量?

如果我在头文件中声明一个变量,在函数中引用会导致编译错误。

<#@ template debug="false" hostspecific="false" language="C#" #>
<#@ output extension=".cs" #>
<# 
     int ValueForThisFile = 35;

     SomeFunction();
#>

<#+
void SomeFunction() {
#>
    public void GeneratedCode() { 
        int value = <#=ValueForThisFile#>;
    }
<#+
}
#>

我知道我可以把它作为参数传递,但是有数百个调用,如果我能避免这种方式,那么语法上会更加紧凑。如果这是一个文件,我可以硬编码该值,但是有几十个具有不同设置和通用包含文件的文件会生成代码。

3个回答

4

我认为这是不可能的。当T4解析你的模板时,实际上会生成一个类。所有的<# #>内容都会被注入到该类的一个方法中,而所有的<#+ #>标记都会作为该类的方法添加,从而允许你从单个方法<# #>标签中调用它们。因此,“ValueForThisFile”变量的范围仅限于该单个方法。举个简单的例子,看看这个模板:

<#@ template debug="false" hostspecific="false" language="C#" #>
<#@ output extension=".cs" #>
<# 
     int ValueForThisFile = 35;

     SomeFunction();
#>

<#+
void SomeFunction() {
   return ValueForThisFile;
}
#>

将生成以下类:

class T4Gen {

private void MainWork() {
    int ValueForThisFile = 35;
    this.SomeFunction();
}

private void SomeFunction{
    return ValueForThisFile;
}

}

变量“ValueForThisFile”仅在MainWork函数中范围有效。实际的T4生成的类更为复杂,但正如您所见,在这种代码中没有办法有全局变量。

谢谢,弗兰克。我注意到它是一个类,因为我注意到我可以调用其他函数,但是我没有整体结构的大局观。 - John Mott
1
如果您想要查看生成的类,可以在模板标签上将debug属性设置为true,它会保存生成的文件。这里是微软的文档(http://msdn.microsoft.com/en-us/library/gg586945.aspx),讲解了如何做到这一点。请查看debug属性部分,它说明了中间代码文件是如何写入%Temp%目录的。 - Frank
4
根据文档的进一步说明,<#+ #>(类特征块)标记可以包含方法、字段和属性。理论上,您在这些块中放置的代码将被注入到类的主体中,因此您可能能够在<#+ #>中放置一个“private int ValueForThisFile;”语句,并能够从<# #>设置它,仍然能够从其他<#+ #>块中定义的方法的主体中访问它。 - Frank
谢谢,我会去查看的。 - John Mott

1

按照这种方式构建您的T4脚本可能会有所帮助,我在我的项目中成功地使用了类似的方法:

<#@ template debug="false" hostspecific="false" language="C#" #>
<#@ output extension=".cs" #>
<#     
    var Context = new ScriptContext();
    Context.SomeFunction();
#>
// This file is generated by Build/Info.tt, do not modify!
void SomeFunction() {
    public void GeneratedCode() { 
        int value = <#=Context.ValueForThisFile#>;
    }
}

<#+
public class ScriptContext {
    public int ValueForThisFile = 35;

    public void SomeFunction()
    {
        ValueForThisFile = 42;
    }
}
#>

1
可以在T4模板中跨函数共享变量,尝试以下代码:
<#@ template  debug="true" hostSpecific="true" #>
<#@ output extension=".cs" #>
<#@ import namespace="System.Collections.Generic" #> 
<#
    InitGlobalVariable();
    AddNames();
    ShowNames();

#>

<#+
    //T4 Shared variables
    List<string> names;
#>

<#+

private void InitGlobalVariable()
{
    names = new List<string>();
}

private void AddNames()
{
    names.Add("Mickey");
    names.Add("Arthur");
}

private void ShowNames()
{
    foreach(var name in names)
    {
#>
        <#= name #>
<#+  
    }
}
#>

在<#+ ... #>内声明变量,然后在<# ... #>内进行初始化。

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