如何用 T4 生成一个简单的类?

Posted

技术标签:

【中文标题】如何用 T4 生成一个简单的类?【英文标题】:How to generate a simple class with T4? 【发布时间】:2017-07-10 06:17:21 【问题描述】:

我正在开发一个 VSPackage,它应该从数据库中的一些数据生成简单的类。我已经有一个静态方法GetFieldInfo 从数据库中获取我需要的数据,GetFieldInfo 返回一个List<TableField>,其中TableField 是一个自定义类,它包含我需要的所有数据。

到目前为止,我的 T4 模板如下所示:

<#@ template language="C#" #>
<#@ assembly name="System.Core" #>
<#@ import namespace="System" #>
<#@ import namespace="System.Collections.Generic" #>
<#@ import namespace="System.Linq" #>
<#@ import namespace="System.Text" #>
<#@ import namespace="System.Threading.Tasks" #>
<#@ output extension=".cs" #>
<#@ parameter name="namespace" type="System.String" #>
<#@ parameter name="className" type="System.String" #>
<#@ parameter name="fields" type="System.Collections.Generic.List<TableField>" #>

namespace <#= this.namespace #>

    public class <#= classname #>
    
        <#
            foreach (TableField campo in fields)
            

            
        #>
    

所有这些(静态方法、自定义类和模板)都在同一个项目的不同命名空间中。这个项目(我们称它为“辅助项目”)不是 VSPackage 项目(它是在 VSPackage 一中作为参考添加的)。

我的问题是,这个模板吐出了 27 个难以理解的错误(例如:Class, delegate, enum, interface or struct expected 在第 2 行第 9 列; expected 在第 7 行第 9 列;method must have a return value 在第 15 行第 18 列)坦率地说,我什至不知道从哪里开始检查。当有许多奇怪的错误时,我的直觉告诉我,通常是因为开发人员忘记添加/配置一些简单的事情,但到目前为止我还没有找到任何可以帮助我的东西。在 Google 中,我没有找到通过 T4 生成类的教程/示例。

我想生成什么?这个:

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;

namespace [TARGET_PROJECT_NAMESPACE]

    public class [TABLE_NAME]
    
        public [FIELD_TYPE] [FIELD_NAME]  get; set; 
    

那么,我做错了什么?

【问题讨论】:

您在模板中使用参数。你将如何将它们传递给模板? @evk 我还没有找到方法。我知道VS provides a templating host我也许可以使用。 这意味着您不需要在设计时生成任何输出。产生这些错误是因为 VS 试图在设计时转换您的模板,但这没有任何意义。所以右键单击您的模板,转到属性并删除“自定义工具”。请注意,您的模板仍然可能是错误的(例如,您使用没有命名空间的 TableField),但这是另一回事。 ...问题来了:也许我应该放弃 T4 并使用旧的 CodeDOM?我最担心的是我的 VSPackage 可以毫无问题地将我生成的类添加到目标项目中。 我没有在 VS 插件中使用 T4 模板的经验。我通常使用它们通过反射检查一些代码并在 design time 中生成另一个代码(所以没有参数)。在这种情况下(设计时生成)它非常有用。在任何其他情况下......怀疑。所以我会说使用任何对你来说更方便的东西。如果您决定仍然使用 T4 模板 - 至少安装 VS 插件,它在那里提供语法突出显示。 【参考方案1】:

抱歉,无法添加评论 - 仍然没有“50 声望”。

首先 - 您需要参考定义 TableField 和您在模板中使用的其他部分的命名空间。添加 。

第二 - 您希望在生成的代码中有很多“使用”语句 - 您需要将它们作为文本放入模板中。

关于 VSPackage - 请记住,您有两个阶段 - 模板编译和代码生成,并且有两个自定义工具可以在第一阶段或两个阶段完成。很可能您需要在开发阶段进行模板编译,并在使用包时执行模板。

提示:如果模板没有做它应该做的事情 - 将模板简化为基本模板 - 让他一次又一次地生成相同的静态代码。

【讨论】:

【参考方案2】:

右键单击您的.tt 文件并确保您的Custom Tool 的值设置为TextTemplatingFilePreProcessor

创建新模板时的样板代码应该为您生成一个类 - 例如,如果您将模板命名为 ***Template.tt,那么您也应该有一个名为 ***Template 的类。

您可以实例化 ***Template 类以将参数添加到模板中,如下所示:

Program.cs

public class Program

    static void Main(string[] args)
    
        List<TableField> fields = new List<TableField>();

        ***Template sft = new ***Template();
        sft.Session = new Dictionary<string, object>();
        sft.Session.Add("_namespace", "TargetProjectNamespace");
        sft.Session.Add("className", "ClassName");
        sft.Session.Add("fields", fields);
        sft.Initialize();
        string output = sft.TransformText();
        Console.WriteLine(output);
        Console.ReadKey();
    

***Template.tt

<#@ template language="C#" #>
<#@ parameter name="_namespace" type="System.String" #>
<#@ parameter name="className" type="System.String" #>
<#@ parameter name="fields" type="System.Collections.Generic.List<TableField>" #>
namespace <#= _namespace #>

    public class <#= className #>
    
        <#
            foreach (TableField campo in fields)
            

            
        #>
    

【讨论】:

以上是关于如何用 T4 生成一个简单的类?的主要内容,如果未能解决你的问题,请参考以下文章

如何用jQuery改变按钮的文字?

T4Toolbox简单了解

T4随记

如何用vs2013开发人员命令提示工具执行一个方法(一个简单的demo)

教你如何用C++创建一个特殊的类

T4MVC 无法生成带有 ErrorGeneratingOutput 的类