2010-07-21 9 views
12

Ich schreibe ein T4-Skript, das bestimmte Klassen widerspiegelt und auf ihnen basierende Codegenerierung bereitstellt. Das Problem ist, dass mein Skript fehlschlägt und sagt, dass auf die Klassen in meinem aktuellen Projekt nicht zugegriffen werden kann.T4 Toolbox - Referenzieren der Klasse in der aktuellen Assembly

Das Skript selbst befindet sich in derselben Assembly wie die Klassen, auf die ich verweisen möchte. Ich habe versucht, den Namespace, die Datei und einen Verweis auf die aktuelle Assembly (das Projekt selbst) zu referenzieren - alles ohne Erfolg.

Was fehlt mir?

Antwort

9

Ich glaube, das ist, was Nicko und uosɐs suchen. Ändern Sie einfach "MyAssembly.CodeGeneration" in den Namen des Projekts mit den T4-Vorlagen.

<#@ assembly name="$(TargetPath)MyAssembly.dll" #> 
<#@ import namespace="MyAssembly.CodeGeneration" #> 
+8

Ich habe stattdessen $ (TargetPath) verwendet. Es ist das Makro für die DLL. <# @ Assemblyname = "$ (TargetPath)" #> <# @ import namespace = "MyAssembly.CodeGeneration" #> –

+0

Es wäre nett gewesen, wenn Sie die ursprüngliche Lösung auch verlassen hätten –

2

Eine Sache im Auge zu behalten ist, dass die T4-Skript zu schreiben sind nicht wirklich „befinden sich in der gleichen Assembly“ - weil es Design-Time-Code ist, nicht Laufzeitcode. Mit anderen Worten - es wird überhaupt nicht in Ihre Baugruppe kompiliert.

Stattdessen wird das T4-Vorlagenskript ausgeführt, während Sie Code schreiben - oder, wenn Sie bestimmte Hooks aktiviert haben, wenn Sie Ihr Programm erstellen/kompilieren. Da es tatsächlich getrennt von Ihrem Projekt, Code ist, hat es jedoch keine Möglichkeit, die Assembly Ihres Projekts direkt zu verweisen - es sei denn, Sie verwenden so etwas wie DTE - das gibt Ihnen die Möglichkeit, auf die Visual Studio-Umgebung zuzugreifen und Elemente zu erkunden wie das aktuell geladene Projekt.

Als Beispiel betrachten wir das folgende Skript:

<#@ template language="C#" debug="false" hostspecific="true" #> 
<#@ output extension=".js" #> 
<#@ assembly name="System" #> 
<#@ assembly name="System.Core" #> 
<#@ assembly name="System.Data.Entity" #> 
<#@ assembly name="EnvDTE" #> 
<#@ import namespace="EnvDTE" #> 
<#@ include file="T4Toolbox.tt" #> 
<#@ import namespace="System" #> 
<#@ import namespace="System.Collections" #> 
<#@ import namespace="System.Collections.Generic" #> 
<#@ import namespace="System.Linq" #> 
<#@ import namespace="System.Reflection" #> 

string targetNamespace = "MyNamespace"; 
var dte = (DTE)TransformationContext.Current.GetService(typeof(DTE)); 
var project = dte.Solution.FindProjectItem(TransformationContext.Current.Host.TemplateFile).ContainingProject); 

var classes = FindClasses(project, targetNamespace, ""); 

<# foreach (CodeClass c in classes) { #> 

    public class <#= c.Name #> { 

<#  var properties = c.Members.OfType<EnvDTE.CodeProperty>() 
      .Where(p => p.Access.HasFlag(vsCMAccess.vsCMAccessPublic)) 
      .OrderBy(p => p.Name); 
     foreach (var prop in properties) { 
#> 

     public <#= prop.Type.AsString #> <#= prop.Name #> { get; set; } 

<#  } #> 

    } 

<# } #> 

<#+ List<CodeClass> FindClasses(Project project, string ns, string className) { 
     List<CodeClass> result = new List<CodeClass>(); 
     FindClasses(project.CodeModel.CodeElements, className, ns, result, false); 
     return result; 
    } 
    void FindClasses(CodeElements elements, string className, string searchNamespace, List<CodeClass> result, bool isNamespaceOk) { 
     if (elements == null) return; 
     foreach (CodeElement element in elements) { 
      if (element is CodeNamespace) { 
       CodeNamespace ns = element as CodeNamespace; 
       if (ns != null) { 
        if (ns.FullName == searchNamespace) 
         FindClasses(ns.Members, className, searchNamespace, result, true); 
        else 
         FindClasses(ns.Members, className, searchNamespace, result, false); 
       } 
      } else if (element is CodeClass && isNamespaceOk) { 
       CodeClass c = element as CodeClass; 
       if (c != null) { 
        if (c.FullName.Contains(className)) 
         result.Add(c); 

        FindClasses(c.Members, className, searchNamespace, result, true); 
       } 
      } 
     } 
    } 

Dieses Skript im Wesentlichen vor, wird einem bestimmten Namespace durchlaufen (in diesem Fall "MyNamespace"), iterieren darin alle Klassen durch, dann wird ein Ausgang neue Codedatei, die nur ihre öffentlichen Eigenschaften mit einer /setter auflistet - im Wesentlichen, ein POCO der Objekte zu produzieren. In einigen meiner Projekte verwende ich eine angepasste Version dieses Codes, um JavaScript-Objekte basierend auf meinen POCOs zu generieren, so dass meine JS-Modelle immer serverseitig mit meinen serverseitigen Objekten synchron sein können.

Der Trick, um es, wenn auch ist, in den ersten Zeilen:

var dte = (DTE)TransformationContext.Current.GetService(typeof(DTE)); 
var project = dte.Solution.FindProjectItem(TransformationContext.Current.Host.TemplateFile).ContainingProject); 
var classes = FindClasses(project, targetNamespace, ""); 

Im Wesentlichen der DTE-Dienst Visual Studio fragt ihm ein abstraktes Modell der aktuell geladenen Solution zu geben und es ist Projects . Wir laden dann die Project, in der die aktuelle TemplateFile gespeichert ist, und analysieren in der FindClasses() Methode die Klassen innerhalb dieses Projekts, die unseren Suchkriterien entsprechen.

Ich hoffe, dass der Beispielcode gibt Ihnen einen Ausgangspunkt zu springen - aber wenn Sie weiteres Detail benötigen, hier sind ein paar zusätzliche Hinweise für Sie Ihre Zähne in sinken:

0

Referenz es üblich Weg.Überprüfen Sie dann, ob die Assembly geladen ist. Wenn nicht, generieren Sie Stub-Code (um die Kompilierung zu ermöglichen; nach der Kompilierung führen Sie T4 erneut aus, um echten Code zu generieren). Und einen Komponententest haben, der verhindern könnte, dass Stub-Code in die Produktion geht.

0

Aus irgendeinem Grund konnte ich nicht @brian Lösung arbeiten. Ich lande dabei In meinem Fall T4Generators war mein eigenes Projekt in der gleichen Lösung.

<#@ assembly name="$(SolutionDir)\T4Generators\bin\Debug\T4Generators.dll" #> 
<#@ import Namespace="T4Generators" #>