调试 T4 文本模板
可以在文本模板中设置断点。 若要调试设计时文本模板,请保存文本模板文件,然后在“解决方案资源管理器”中文件的快捷菜单上选择“调试 T4 模板”。 若要调试运行时文本模板,只需调试它所属的应用程序。
若要调试文本模板,应了解模板转换过程的步骤。 每个步骤中可能会发生不同类型的错误。 步骤如下所示。
步骤 | 设计时模板:发生时 | 运行时模板:发生时 |
---|---|---|
代码从文本模板生成。 指令中的错误,或者不匹配或无序的 <#...#> 标签。 |
保存模板或调用文本转换时。 | 保存模板或调用文本转换时。 |
生成的代码已编译。 模板代码中的编译错误。 |
紧随上一步操作。 | 连同应用程序代码。 |
代码运行。 模板代码中的运行时错误。 |
紧随上一步操作。 | 应用程序运行并调用模板代码时。 |
在大多数情况下,错误报告中会包括模板代码中的行号。 如果错误报告引用临时文件名,这通常是因为文本模板代码中出现不匹配的方括号。
可以在文本模板中设置断点,然后按常规方式进行调试。
常见错误和修补程序
下表列出了最常见的错误及其修补程序。
错误消息 | 说明 | 解决方案 |
---|---|---|
未能加载 Transformation 类要继承的基类“{0}”。 | 如果在模板指令的 inherits 参数中找不到指定的基类,则会发生此错误。 消息提供了 template 指令的行号。 |
确保指定的类存在,并且它所在的程序集在 assembly 指令中指定。 |
未能解析文件 {0} 的包含文本 | 找不到包含的模板时会发生此错误。 消息提供了所请求的包含文件的名称。 | 确保文件路径相对于原始模板路径,或者文件位于在主机注册的位置,或者文件有完整路径。 |
初始化转换对象时会生成错误。 将不会运行转换。 | 转换类的“Initialize()”失败或返回 false 时发生此错误。 | Initialize() 函数中的代码来自 <#@template#> 指令中指定的基转换类和指令处理器。 导致初始化失败的错误可能位于错误列表中。 调查失败的原因。 可以按照调试模板的过程查看 Initialize() 的实际生成代码。 |
未向指令处理器“{1}”的程序集“{0}”授予 FullTrust 权限集。 仅允许受信任的程序集提供指令处理器。 不会加载此指令处理器。 | 如果系统不向包含指令处理器的程序集授予 FullTrust 权限,则会出现此错误。 消息提供程序集的名称和指令处理器的名称。 | 请确保仅在本地计算机上使用受信任的程序集。 |
路径“{0}”必须是此计算机或部分受信任区域的的本地路径。 | 如果指令或 assembly 指令引用不在本地计算机或网络受信任区域上的文件,则会出现此错误。 | 请确保指令或 assembly 指令所在的目录位于受信任的区域中。 可以通过 Internet Explorer 将网络目录添加到受信任区域。 |
多个语法错误,例如“无效令牌 catch”或“命名空间不能直接包含成员” | 模板代码中的右大括号太多。 编译器将它与标准生成代码混淆。 | 检查代码分隔符内的右大括号和方括号的数量。 |
未正确编译或执行的循环或条件。 例如:<#if (i>10)#> Number is: <#= i #> 。此代码始终输出 i 值。 只有“Number is:”是条件。 |
在 C# 中,始终使用大括号将嵌入在控制语句中的文本块括起来。 | 添加大括号:<#if (i>10) { #> Number is: <#= i #><# } #> 。 |
处理设计时模板或编译运行时(预处理)模板时,“表达式太复杂”。 尝试检查运行时模板生成的代码时,Visual Studio 会停止工作。 |
文本块太长。 T4 将文本块转换为字符串串联表达式,每个模板行都有一个字符串字面量。 非常长的文本块可能会超过编译器的大小限制。 | 使用表达式块分解长文本块,例如:<#= "" #> |
警告说明和修补程序
下表列出了最常见的警告以及修补程序(如果可用)。
警告消息 | 说明 | 解决方案 |
---|---|---|
加载包含文件“{0}”时返回了 null 或空字符串。 | 如果包含的文本模板文件为空,则会发生此错误。 消息提供了包含的文件的文件名。 | 删除 include 指令或确保文件包含某些内容。 |
编译转换: | 在编译器编译转换时,在所有源自编译器的错误或警告前面添加此字符串。 此字符串表示编译器引发了错误或警告。 | 如果在查找 DLL 时出现问题,可能需要提供完整路径或完全限定的强名称(如果 DLL 位于 GAC 中)。 |
“{0}”参数在指令中已存在。 将忽略重复参数。 | 如果指令中多次指定参数,则会出现此警告。 消息提供了参数的名称和指令的行号。 | 删除重复的参数规范。 |
加载包含文件“{0}”时出现错误。 将忽略 include 指令。 | 如果找不到 include 指令中指定的文件,则会出现此警告。 消息提供了文件名和指令的行号。 |
请确保包含文件与原始文本模板文件位于同一目录中,或者存在于向主机注册的其中一个包含目录中。 |
为 Transformation 类指定了无效的基类。 基类必须派生自 Microsoft.VisualStudio.TextTemplating.TextTransformation。 | 如果 template 指令中的 inherits 参数指定的类并非继承自 TextTransformation ,则会出现此警告。 消息提供了 template 指令的行号。 |
指定一个派生自 TextTransformation 的类。 |
在“template”指令中指定了无效的区域性。 区域性的格式必须为“xx-XX”。 将使用固定区域性。 | 如果未正确指定 template 指令中的 culture 参数,则会出现此警告。 消息提供了 template 指令的行号。 | 将 culture 参数更改为“xx-XX”格式的有效区域性。 |
在 template 指令中指定了无效的调试值“{0}”。 值必须为“true”或“false”。 将使用默认值“false”。 | 如果未正确指定 template 指令中的 debug 参数,则会出现此警告。 消息提供了 template 指令的行号。 |
将 debug 参数设置为“true”或“false”。 |
在 template 指令中指定了无效的 HostSpecific 值“{0}”。 HostSpecific 值必须是“true”或“false”。 将使用默认值“false”。 | 如果未正确指定 template 指令中的 host-specific 参数,则会出现此警告。 消息提供了 template 指令的行号。 |
将 host-specific 参数设置为“true”或“false”。 |
在“template”指令中指定了无效的语言“{0}”。 语言必须是“C#”或“VB”。 将使用默认值“C#”。 | 如果在 template 指令中指定了不受支持的语言,则会出现此警告。 仅允许使用“C#”或“VB”(不区分大小写)。 消息提供了 template 指令的行号。 |
将 template 指令中的 language 参数设置为“C#”或“VB”。 |
在模板中发现多个 output 指令。 所有项(第一项除外)都将被忽略。 | 如果在模板文件中指定多个 output 指令,则会出现此警告。 消息提供了重复的 output 指令的行号。 |
删除重复的 output 指令。 |
在模板中发现多个 template 指令。 所有项(第一项除外)都将被忽略。 应在一个 template 指令中指定 template 指令的多个参数。 | 如果在文本模板文件(包括包含文件)中指定多个 template 指令,则会出现此警告。 消息提供了重复的 template 指令的行号。 |
将不同 template 指令聚合为一个 template 指令。 |
没有为名为“{0}”的指令指定任何处理器。 将忽略该指令。 | 如果指定 custom 指令,但未提供 processor 属性,则会出现此警告。 消息提供了指令的名称和行号。 |
为指令提供包含 directive 处理器名称的 processor 属性。 |
无法为名为“{1}”的指令找到名为“{0}”的处理器。 将忽略该指令。 | 如果系统找不到 custom 指令中指定的 directive 处理器,则会出现此警告。 消息提供了指令名称、处理器名称和指令的行号。 |
将指令中的 processor 属性设置为指令处理器的名称。 |
找不到指令“{1}”所需的参数“{0}”。 将忽略该指令。 | 如果系统未提供所需的指令参数,则会出现此警告。 消息提供了缺少的参数的名称、指令名称和行号。 | 提供了缺少的参数。 |
名为“{0}”的处理器不支持名为“{1}”的指令。 将忽略该指令。 | 如果指令处理器不支持某个指令,则会出现此警告。 消息提供了 offending 指令的名称和行号以及指令处理器的名称。 | 更正指令的名称。 |
文件“{0}”的 include 指令导致无限循环。 | 如果指定了循环 include 指令(例如,文件 A 包含文件 B,而文件 B 包含文件 A),则会显示此消息。 | 不要指定循环 include 指令。 |
运行转换: | 在运行转换时将生成的所有错误或警告前面添加此字符串。 | 不适用。 |
在块中发现意外的开始或结束标记。 请确保未错误键入开始或结束标记,并确保模板中没有任何嵌套块。 | 如果出现意外的 <# 或 #>,则会显示此消息。 也就是在未结束的另一个开始标记之后出现了 <#,或者在它前面不存在未结束的开始标记时出现了 #>。 消息提供了不匹配标记的行号。 | 删除不匹配的开始或结束标记,或使用转义字符。 |
以错误的格式指定了指令。 将忽略该指令。 请以 <#@ name [parametername="parametervalue"]* #> 格式指定指令 |
如果未以正确的格式指定指令,则由分析程序显示。 消息提供了不正确的指令的行号。 | 确保所有指令均为 <#@ name [parametername="parametervalue"]* #> 格式。 有关详细信息,请参阅 T4 文本模板指令。 |
未能为已注册的指令处理器“{1}”加载程序集“{0}” {2} |
如果主机无法加载指令处理器,则会出现此警告。 消息标识了为指令处理器提供的程序集和指令处理器的名称。 | 请确保指令处理器已正确注册并且该程序集存在。 |
未能在程序集“{1}”中为已注册的指令处理器“{2}”找到类型“{0}” {3} |
如果无法从程序集加载指令处理器类型,则会出现此警告。 消息提供了类型、程序集和指令处理器的名称。 | vshost 在注册表中查找指令处理器信息(名称、程序集和类型)。 请确保指令处理器已正确注册,并且该类型存在于程序集中。 |
加载程序集“{0}”时出现问题 | 如果加载程序集时出现问题,则会出现此警告。 消息提供了程序集的名称。 | 可以指定要在 <@#assembly#> 指令中以及由指令处理器加载的程序集。 此字符串后面的错误消息会提供有关程序集加载失败原因的更多数据。 |
为名为“{1}”的指令创建和初始化处理器时出现问题。 处理器的类型为 {0}。 将忽略该指令。 | 如果系统无法创建或初始化指令处理器,则会出现此警告。 消息提供了指令的名称和行号,以及处理器的类型。 | 请确保使用正确的指令处理器,并且指令处理器具有公共的默认构造函数。 否则,请使用调试选项来找出指令处理器的 Initialize() 方法失败的原因。 有关详细信息,请参阅排查文本模板问题。 |
处理名为“{0}”的指令时引发了异常。 | 如果指令处理器在处理指令时引发异常,则会出现此警告。 | 请确保指令处理器的参数正确无误。 |
主机在尝试解析程序集引用“{0}”时引发了异常。 | 如果主机尝试解析程序集引用时引发异常,则会出现此警告。 消息提供了程序集引用字符串。 | 程序集引用来自 <@#assembly#> 指令和指令处理器。 请确保程序集参数中提供的“name”参数正确无误。 |
尝试为指令 {2} 指定不受支持的 {1} 值 {0} | 提供不受支持的 requires 或 provides 参数时,由 RequiresProvidesDirectiveProcessor(所有生成的指令处理器均派生自它)引发此消息。 | 确保 requires 和 provides 参数中提供的 name='value' 对中的名称正确。 |