2014-04-24 39 views
9

Próba uruchomienia szablonów T4 dla Immutable Object Graph daje błędyraporty T4 Kompilacja transformacji: Nieprawidłowy token „to” w klasie, struct

╔═══════╦═══╦══════════════════════════════════════════════════════════════════════════════════════════════════╦═════════════════════════════════════════════════════════╦═══╦════╦══════╗ 
║ 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 ║ 
╚═══════╩═══╩══════════════════════════════════════════════════════════════════════════════════════════════════╩═════════════════════════════════════════════════════════╩═══╩════╩══════╝ 

Linia zgłaszane jest zawsze linia 1, a pełny zestaw szablonów t4 to setki linii. Jak mogę rozwiązać ten problem i rozwiązać ten problem?

+0

Chociaż poniżej odpowiedź jest poprawna, jeśli korzystasz z GitHub, następujący artykuł może również wyjaśnić alternatywne rozwiązanie - https://www.teamdevelopmentforsitecore.com/Blog/t4-transform-file-problems-code-gen – woodyiii

+0

@ woodyiii, może się okazać, że dodanie poprawnego specyfikatora eol do '.gitattributes' bardziej trwale rozwiąże Twój problem. Ręczna zmiana może się szybko zestarzeć, jeśli członkowie zespołu są na innych platformach. – Mitch

Odpowiedz

27

Po skryptorze nie można mieć literałów w szablonie T4.

Zmień

<#@ template debug="true" language="C#" #> 
<#+ 
// scriptlet 
#> 
               <-- empty line here 

Aby

<#@ template debug="true" language="C#" #> 
<#+ 
// scriptlet 
#> 

debugowanie

Możesz zobaczyć C# jest generowany przez silnik T4 wywołując PreProcessTemplate z hostem niestandardowych szablonów.

że zmodyfikowany Custom Template Host sample do tego celu:

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(); 
     } 
    } 
} 

Badanie transformatora generowane z szablonu wykazała następujące wiersze poza sposobem TransformText(). Pozornie wszelkie literały w szablonach źródłowych, które pojawiły się po scriptlet (<#+ #>) zostaną umieszczone w poprawce do wygenerowanej klasy generatora.

 #line 1 "C:\dev\ImmutableObjectGraph-master\2013\Demo\Fruit.tt" 
this.Write("\n"); 

Usunięcie nowych znaków na końcu każdego pliku szablonu rozwiązało problem.

+2

Sądzę, że ta informacja jest najważniejsza dla 99% czytelników: "Usunięcie znaków nowej linii na końcu każdego pliku szablonu rozwiązało problem." – Maxim

+0

Dziękuję bardzo, odrąbałem sobie włosy na godzinę próbując zrozumieć, co się dzieje – Atario

+0

Dla mnie problem był gdzie indziej. 1. Weźmy przykładowy kod Szymon Šeliga z powyższym 2. Wklej do aplikacji konsoli 3. Zainstaluj Nuget „Microsoft.VisualStudio.TextTemplating.15.0” ścieżki 4. hardcode do swojego .tt pliku * (powinny być na zastawie 111) 5. spowoduje wygenerowanie * .tt.generator.cs 6. otwórz ten plik w Visual Studio 7. poszukaj this.Write ("\ n"); które są metodami zewnętrznymi (składnia visual studio intelisense wil laktualnie podkreślona czerwonym: – ambidexterous

4

Dla mnie końcowy znak nowej linii na końcu pliku nie stanowił problemu, ale posiadanie końcówek linii Unix (\ n) zamiast końcówek linii systemu Windows (\ r \ n) spowodowało uszkodzenie silnika T4.

Bardzo frustrujące dla debugowania, gdy masz dwa pliki, które wyglądają identycznie, ale jeden z nich nie będzie się kompilować!

+0

W moim przypadku ta odpowiedź rozwiązała mój problem i ten artykuł wyjaśnia, jak szczegółowo rozwiązać problem - https: //www.teamdevelopmentforsitecore.com/Blog/t4-transform-file-problems-code-gen Za każdym razem, gdy konwertowaliśmy naszą kontrolę wersji na GitHub, pojawiły się przypadkowe problemy z CR LF, które wciąż pojawiają się, jak ten. – woodyiii

+0

"Windows lub popiersie!" oni powiedzieli. Co mogłoby pójść źle? –