2010-07-21 49 views
12

我正在寫一個T4腳本,它反映了某些類並提供了基於它們的代碼生成。問題是我的腳本錯誤,說我的當前項目中的類不能被訪問。T4 Toolbox - 在當前程序集中引用類

腳本本身駐留在相同的組件,我想引用的類。我已經嘗試引用名稱空間,文件並添加對當前程序集(項目本身)的引用 - 都無濟於事。

我錯過了什麼?

回答

9

我相信這是力高和uosɐs正在尋找。只需使用T4模板將「MyAssembly.CodeGeneration」更改爲項目名稱即可。

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

改爲使用$(TargetPath)。這是dll的宏。 <#@程序集名稱=「$(TargetPath)」#> <#@ import namespace =「MyAssembly.CodeGeneration」#> – 2013-01-18 20:51:52

+0

如果您還保留原始解決方案 – 2017-03-25 01:15:46

2

有一點要記住的是,你正在寫的T4腳本並不是真的「駐留在同一總成」 - 因爲這是設計時的代碼,而不是運行時代碼。換句話說 - 它不會被編譯到您的程序集中,完全不在

相反,當你在編寫代碼的T4模板腳本運行 - 或者,如果你啓用了某些掛鉤,只要構建/編譯程序。因爲它從你的項目實際上獨立是,代碼,但是,它直接沒有引用您的項目的裝配能力 - 除非你使用類似DTE - 它給你訪問的Visual Studio環境本身的能力,並探討元素如當前加載的項目。

作爲一個例子,考慮下面的腳本:

<#@ 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); 
       } 
      } 
     } 
    } 

此腳本,在本質上,將通過一個特定的命名空間運行(在此情況下"MyNamespace"),迭代通過所有的類的在其中,然後輸出一個新的代碼文件,其中只列出了它們的公共屬性,其中getter/setter - 實質上是產生對象的POCO。在我的一些項目中,我使用此代碼的改編版本來基於我的POCO生成JavaScript對象,以便從序列化的角度來看,我的JS模型始終可以與我的服務器端對象同步。

的竅門吧,雖然是在第幾行:

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

在本質上,DTE業務是問Visual Studio中給它當前加載Solution的抽象模型,它是Projects 。然後,我們加載在當前TemplateFile存儲在Project,並在FindClasses()方法,該項目符合我們的搜索標準,其內解析出的類。

我希望示例代碼爲您提供了一個起點,從跳下 - 但如果你需要進一步的細節,這裏有一些額外的參考,爲您的牙齒沉入:

0

參考它常見的方式。然後檢查程序集是否被加載,如果沒有 - 生成存根代碼(使編譯成爲可能;編譯後再次運行T4以生成實際代碼)。並有單元測試,可以防止存根代碼生產。

0

出於某種原因,我無法獲得@brian解決方案的工作。我結束了這樣做 在我的情況下,T4Generators是我在同一解決方案中的獨立項目。

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