我正在寫一個T4腳本,它反映了某些類並提供了基於它們的代碼生成。問題是我的腳本錯誤,說我的當前項目中的類不能被訪問。T4 Toolbox - 在當前程序集中引用類
腳本本身駐留在相同的組件,我想引用的類。我已經嘗試引用名稱空間,文件並添加對當前程序集(項目本身)的引用 - 都無濟於事。
我錯過了什麼?
我正在寫一個T4腳本,它反映了某些類並提供了基於它們的代碼生成。問題是我的腳本錯誤,說我的當前項目中的類不能被訪問。T4 Toolbox - 在當前程序集中引用類
腳本本身駐留在相同的組件,我想引用的類。我已經嘗試引用名稱空間,文件並添加對當前程序集(項目本身)的引用 - 都無濟於事。
我錯過了什麼?
我相信這是力高和uosɐs正在尋找。只需使用T4模板將「MyAssembly.CodeGeneration」更改爲項目名稱即可。
<#@ assembly name="$(TargetPath)MyAssembly.dll" #>
<#@ import namespace="MyAssembly.CodeGeneration" #>
有一點要記住的是,你正在寫的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()
方法,該項目符合我們的搜索標準,其內解析出的類。
我希望示例代碼爲您提供了一個起點,從跳下 - 但如果你需要進一步的細節,這裏有一些額外的參考,爲您的牙齒沉入:
參考它常見的方式。然後檢查程序集是否被加載,如果沒有 - 生成存根代碼(使編譯成爲可能;編譯後再次運行T4以生成實際代碼)。並有單元測試,可以防止存根代碼生產。
出於某種原因,我無法獲得@brian解決方案的工作。我結束了這樣做 在我的情況下,T4Generators是我在同一解決方案中的獨立項目。
<#@ assembly name="$(SolutionDir)\T4Generators\bin\Debug\T4Generators.dll" #>
<#@ import Namespace="T4Generators" #>
改爲使用$(TargetPath)。這是dll的宏。 <#@程序集名稱=「$(TargetPath)」#> <#@ import namespace =「MyAssembly.CodeGeneration」#> – 2013-01-18 20:51:52
如果您還保留原始解決方案 – 2017-03-25 01:15:46