尝试运行Immutable Object Graph的T4模板会产生错误
╔═══════╦═══╦══════════════════════════════════════════════════════════════════════════════════════════════════╦═════════════════════════════════════════════════════════╦═══╦════╦══════╗
║ Error ║ 5 ║ Compiling transformation: Invalid token 'this' in class, struct, or interface member declaration ║ c:\dev\ImmutableObjectGraph-master\2013\Demo\Message.tt ║ 1 ║ 1 ║ Demo ║
║ Error ║ 6 ║ Compiling transformation: Method must have a return type ║ c:\dev\ImmutableObjectGraph-master\2013\Demo\Message.tt ║ 1 ║ 6 ║ Demo ║
║ Error ║ 7 ║ Compiling transformation: Type expected ║ c:\dev\ImmutableObjectGraph-master\2013\Demo\Message.tt ║ 1 ║ 12 ║ Demo ║
╚═══════╩═══╩══════════════════════════════════════════════════════════════════════════════════════════════════╩═════════════════════════════════════════════════════════╩═══╩════╩══════╝
报告的行总是第1行,而整套t4模板是数百行。如何排除故障并解决此问题?
答案 0 :(得分:35)
在scriptlet之后,你不能在T4模板中使用文字。
更改
<#@ template debug="true" language="C#" #>
<#+
// scriptlet
#>
<-- empty line here
要
<#@ template debug="true" language="C#" #>
<#+
// scriptlet
#>
您可以通过使用自定义模板主机调用PreProcessTemplate
来查看T4引擎生成的C#。
我为此修改了Custom Template Host sample:
using Microsoft.VisualStudio.TextTemplating;
using System;
using System.CodeDom.Compiler;
using System.Collections.Generic;
using System.IO;
using System.Text;
namespace CustomHost
{
class CustomCmdLineHost : ITextTemplatingEngineHost
{
public string TemplateFile { get; private set; }
public string FileExtension { get; private set; }
public Encoding FileEncoding { get; private set; }
public CompilerErrorCollection Errors { get; private set; }
public IList<string> StandardAssemblyReferences { get { return new[] { typeof(System.Uri).Assembly.Location }; } }
public IList<string> StandardImports { get { return new string[] { "System" }; } }
public CustomCmdLineHost(string file)
{
this.TemplateFile = file;
this.FileEncoding = Encoding.UTF8;
this.FileExtension = ".txt";
}
public bool LoadIncludeText(string requestFileName, out string content, out string location)
{
content = location = String.Empty;
if (File.Exists(requestFileName))
{
content = File.ReadAllText(requestFileName);
return true;
}
return false;
}
public object GetHostOption(string optionName)
{
object returnObject;
switch (optionName)
{
case "CacheAssemblies":
returnObject = true;
break;
default:
returnObject = null;
break;
}
return returnObject;
}
public string ResolveAssemblyReference(string assemblyReference)
{
return ResolvePath(assemblyReference);
}
public Type ResolveDirectiveProcessor(string processorName)
{
throw new Exception("Directive Processor not found");
}
public string ResolvePath(string fileName)
{
if (File.Exists(fileName))
{
return fileName;
}
string candidate = Path.Combine(Path.GetDirectoryName(this.TemplateFile), fileName);
if (File.Exists(candidate))
{
return candidate;
}
return fileName;
}
public string ResolveParameterValue(string directiveId, string processorName, string parameterName)
{
return String.Empty;
}
public void SetFileExtension(string extension)
{
FileExtension = extension;
}
public void SetOutputEncoding(System.Text.Encoding encoding, bool fromOutputDirective)
{
FileEncoding = encoding;
}
public void LogErrors(CompilerErrorCollection errors)
{
Errors = errors;
}
public AppDomain ProvideTemplatingAppDomain(string content)
{
return AppDomain.CreateDomain("Generation App Domain");
}
}
class Program
{
static void Main(string[] args)
{
var templateFileName = args[0];
CustomCmdLineHost host = new CustomCmdLineHost(templateFileName);
Engine engine = new Engine();
string language;
string[] refs;
var output = engine.PreprocessTemplate(
// input file
File.ReadAllText(templateFileName), host,
"testClass", "testNamespace", out language, out refs);
string outputFileName = Path.Combine(
Path.GetDirectoryName(templateFileName),
templateFileName + ".generator.cs");
File.WriteAllText(outputFileName, output, host.FileEncoding);
foreach (CompilerError error in host.Errors)
Console.WriteLine(error.ToString());
Console.ReadLine();
}
}
}
检查从模板生成的变换器在TransformText()
方法之外显示如下行。看起来,在scriptlet(<#+ #>
)之后的源模板中的任何文字都将被置于生成的生成器类中。
#line 1 "C:\dev\ImmutableObjectGraph-master\2013\Demo\Fruit.tt"
this.Write("\n");
删除每个模板文件末尾的换行符解决了这个问题。
答案 1 :(得分:8)
对我来说,文件末尾的尾部换行没有问题,但是使用Unix行结尾(\ n)而不是Windows行结尾(\ r \ n)打破了T4引擎。
当你有两个看起来完全相同但其中一个文件不能编译的文件时调试非常令人沮丧!
答案 2 :(得分:1)
是的,这也与行尾相关,这可能是由于源代码控制所致。
为解决此问题,我将模板代码复制并粘贴到Notepad ++中,并保存为普通的txt文件,然后复制并粘贴回去。
(记事本由于行尾错误而无法正常工作)