使用 Visual Studio 和文本模板转换工具包 (T4) 自动生成代码

更新页 :
页面创建日期 :

操作环境

Visual Studio的
  • Visual Studio 2022
。网
  • .NET 8.0
窗户
  • 窗户11

先决条件

Visual Studio的
  • 它甚至可以使用稍旧的版本
。网
  • 它甚至可以使用稍旧的版本

起先

通常,在创建代码时,您认为您将通过手动输入字符来创建代码,但是如果您想根据特定法律需要创建的代码或数据创建代码,那么能够自动生成它很方便。 本节介绍如何使用文本模板转换工具包(T4)自动生成代码。

由于 T4 是一种脚本格式,因此在创建 T4 文件后立即在 Visual Studio 中生成代码非常容易。 据记载,它会自动生成代码,但生成的只是文本,因此除了程序之外,还可以生成任何文本格式的内容,例如XML和JSON。

这个技巧的主要目的是解释在 T4 中实际自动生成代码的步骤,所以我不会深入探讨 T4 的细节。 如果你曾经用 C# 编写过一个程序,你就会立即理解它。 如果您想了解更多关于T4的信息,请查看官方网站和其他网站。

前提

此提示假定满足以下条件:

  • 在 Windows 上安装的 Visual Studio
  • 了解 C#

T4 可以在大多数项目中使用,但少数项目除外,因此您在安装过程中基本上可以自由选择工作负载。

创建项目

如前所述,T4 可以在大多数项目中使用,但少数项目除外,因此创建什么类型的项目并不重要。 在本例中,我们将为控制台应用创建一个项目。

创建 T4 文件 (.tt)

右键单击项目文件或文件夹以添加新项。

单击“查看所有模板”按钮。

从左侧的树中选择“常规”,从中间的列表中选择“文本模板”。 文件名是任意的。

创建文件后,您可能会立即看到一个类似于下面的对话框。 当自动生成 T4 文件时,将显示此消息。 每次保存或查看文件时,都会自动生成 T4 文件。 如果要按原样执行自动生成过程,请单击“确定”按钮。 如果您不希望对话框每次都显示,请选中“不再显示此消息”。 请注意,如果 T4 文件中描述了对话框中所述的非法进程,则将相应地执行该进程。

添加文件后,可以看到 .tt 文件已添加到解决方案资源管理器中。

该文件的内容如下。

如果在解决方案资源管理器中提取 .tt 文件,您将看到一个同名的文本文件。 这将是自动生成的文件。 由于我们还没有编写任何内容,因此文件的内容是空的。

将自动生成的文件设为.cs文件

如果您使用的是 T4,您很可能希望使用 .cs 扩展而不是默认的 .txt,因为您的程序代码将自动生成。 在这种情况下,请打开 .tt 文件并使用 output extension .cs 保存。

自动生成的文件现在应具有.cs扩展名。 文件名本身与 .tt 文件相同,因此,如果要更改它,请更改 .tt 文件的名称。

暂时,编写一些东西并将其输出到自动生成的文件中

在 T4 中,您编写的内容基本上按原样输出。 <# ... #> 是 T4 进程,其余部分是实际输出文本。

例如,让我们将其放在 .tt 文件中,如下所示。

<#@ template debug="false" hostspecific="false" language="C#" #>
<#@ assembly name="System.Core" #>
<#@ import namespace="System.Linq" #>
<#@ import namespace="System.Text" #>
<#@ import namespace="System.Collections.Generic" #>
<#@ output extension=".cs" #>

public static class Sample
{
  public static void Hello()
  {
    Console.WriteLine("Hello T4!!");
  }
}

当您保存它时,自动生成的文件应完全按照您编写的方式输出。

输出是代码,所以当然也可以从Program.cs调用。

尝试自动生成代码

如上所述,我已经确认我写的内容将按原样输出,但这与我通常编写的内容没有什么不同。 现在,让我们实际使用 T4 脚本来自动生成代码。 制作方法有很多种,所以请在这里只做一个简短的解释,然后按照你想要的方式重新制作。

这一次,作为一个示例,让我们创建一个方法,该方法将每种类型的 parse 方法添加到字符串中,如果无法转换,则返回 ParseXXXX 指定的默认值。 这只是一个创作示例,因此,如果您觉得缺少任何部分,请添加它。

如果你能在不解释细节的情况下理解 C#,看到它会更快,所以我会先发布完整的代码。

<#@ template debug="false" hostspecific="false" language="C#" #>
<#@ assembly name="System.Core" #>
<#@ import namespace="System.Linq" #>
<#@ import namespace="System.Text" #>
<#@ import namespace="System.Collections.Generic" #>
<#@ output extension=".cs" #>

<#
  List<string> types = new(){"Int", "Short", "Long", "Float", "Double", "Decimal"}; 
#>

public static class ParseExtensions
{
<# foreach (var type in types) { #>
<#   var typeLower = type.ToLower(); #>
  public static <#= typeLower #> Parse<#= type #>(this string self, <#= typeLower #> defaultValue)
  {
    return <#= typeLower #>.TryParse(self, out var val) ? val : defaultValue;
  }
<# } #>
}

我们正在做的是定义首次创建的类型 List ,然后将它们转换 foreach 以生成该数量的方法。 T4 的脚本部分是用 C# 编写的,所以如果你懂 C#,你应该能够理解它。

执行此操作时,将生成以下代码:

public static class ParseExtensions
{
  public static int ParseInt(this string self, int defaultValue)
  {
    return int.TryParse(self, out var val) ? val : defaultValue;
  }
  public static short ParseShort(this string self, short defaultValue)
  {
    return short.TryParse(self, out var val) ? val : defaultValue;
  }
  public static long ParseLong(this string self, long defaultValue)
  {
    return long.TryParse(self, out var val) ? val : defaultValue;
  }
  public static float ParseFloat(this string self, float defaultValue)
  {
    return float.TryParse(self, out var val) ? val : defaultValue;
  }
  public static double ParseDouble(this string self, double defaultValue)
  {
    return double.TryParse(self, out var val) ? val : defaultValue;
  }
  public static decimal ParseDecimal(this string self, decimal defaultValue)
  {
    return decimal.TryParse(self, out var val) ? val : defaultValue;
  }
}

生成的是代码,因此您可以按原样在程序中使用它。

关于 T4 的更多信息

即使 T4 脚本部分可以用 C# 编写,也必须将 T4 C# 代码与实际生成的 C# 代码分开。 做出这种区分 <# .... #> 的部分是 。 <# .... #> 是作为脚本执行的代码,而不是在 T4 的脚本部分实际输出的代码。

<# .... #> 由于 C# 本身的内容保持不变,因此没有对其进行解释,但是 <# .... #> 有几种类型的帧。 每种方法都有以下几种使用方法。

代码 说明
<#@ .... #> 它主要用于各种头的声明。 它用在 和 import 声明的 assembly T4 代码的开头。
<# .... #> 编写由 T4 处理的代码。 它可以分为多条线。 此范围内描述的任何内容仅充当操作,不会影响输出文本。
<#= .... #> 当您想要将值(如变量)输出为输出结果时,可以使用此选项。 string text = "Sample"; 例如,如果你写了一个名为 的变量 <#= text #> ,将会 Sample 输出。
<#+ .... #> 用于定义类和方法。 基本上,它写在 T4 文件的末尾。

关于 T4 编辑器

如果 Visual Studio 中没有扩展名,打开 .tt 文件将以黑白文本显示,没有颜色,这很难看到。

其中一些可能会以易于阅读的方式显示 .tt 文件的扩展名,因此请找到您喜欢的那个。 由于它是由志愿者制作的,因此内容可能会根据一年中的时间和 Visual Studio 的版本而变化。 可以从 Visual Studio 菜单中的“扩展”下添加扩展。

这是我在 Visual Studio 2022 中看到的内容,其中包含一个名为“T4 语言”的扩展。