2010-07-21 21 views
12

Tôi đang viết kịch bản T4 phản ánh qua các lớp nhất định và cung cấp tạo mã dựa trên chúng. Vấn đề là kịch bản của tôi lỗi, nói rằng các lớp trong dự án hiện tại của tôi không thể được truy cập.Hộp công cụ T4 - Lớp tham chiếu trong hội hiện tại

Bản thân tập lệnh nằm trong cùng một nhóm với các lớp mà tôi đang cố tham khảo. Tôi đã thử tham chiếu không gian tên, tệp và thêm tham chiếu đến assembly hiện tại (bản thân dự án) - tất cả đều không có kết quả.

Tôi đang thiếu gì?

Trả lời

9

Tôi tin rằng đây là những gì Nicko và uosɐſ đang tìm kiếm. Chỉ cần thay đổi "MyAssembly.CodeGeneration" thành tên của dự án với các mẫu T4.

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

Tôi đã sử dụng $ (TargetPath) thay thế. Đó là macro cho dll. <# @ assembly name = "$ (TargetPath)" #> <# @ import namespace = "MyAssembly.CodeGeneration" #> –

+0

Sẽ rất tuyệt nếu bạn rời giải pháp gốc –

2

Một điều cần ghi nhớ là tập lệnh T4 bạn đang viết không thực sự "nằm trong cùng một cụm" - bởi vì đó là mã thời gian thiết kế, không phải mã thời gian chạy. Nói cách khác - nó không được biên dịch vào assembly của bạn ở tất cả.

Thay vào đó, tập lệnh mẫu T4 chạy trong khi bạn đang viết mã - hoặc, nếu bạn đã bật móc nhất định, bất cứ khi nào bạn xây dựng/biên dịch chương trình của mình. Bởi vì nó thực sự là riêng biệt là từ dự án, mã của bạn, không có khả năng tham chiếu trực tiếp đến dự án của bạn - trừ khi bạn sử dụng một cái gì đó như DTE - mang đến cho bạn khả năng truy cập vào môi trường Visual Studio và khám phá các phần tử chẳng hạn như dự án hiện đang được tải.

Như một ví dụ, hãy xem xét kịch bản sau đây:

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

kịch bản này, trong bản chất, sẽ chạy qua một không gian tên cụ thể (trong trường hợp này "MyNamespace"), lặp qua tất cả các lớp học trong đó, sau đó sản lượng một tệp mã mới chỉ liệt kê các thuộc tính công khai của chúng với một getter/setter - về bản chất, tạo ra một POCO của các đối tượng. Trong một số dự án của tôi, tôi sử dụng một phiên bản thích hợp của mã này để tạo các đối tượng JavaScript dựa trên các POCO của tôi, để các mô hình JS của tôi luôn có thể đồng bộ với các đối tượng phía máy chủ của tôi, từ phối cảnh tuần tự hóa.

Các mẹo để thực hiện, tuy nhiên, là trong vài dòng đầu tiên:

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

Về bản chất, các dịch vụ DTE được hỏi Visual Studio cung cấp cho nó một mô hình trừu tượng của hiện nạp Solution và nó Projects . Sau đó chúng tôi tải lên Project trong đó TemplateFile hiện tại được lưu trữ và trong phương thức FindClasses(), phân tích các lớp trong dự án phù hợp với tiêu chí tìm kiếm của chúng tôi.

Tôi hy vọng các mã ví dụ cho bạn một điểm khởi đầu để nhảy ra khỏi từ - nhưng nếu bạn cần biết thêm chi tiết, đây là một vài tài liệu tham khảo bổ sung để bạn chìm răng của bạn vào:

0

tham khảo nó theo cách thông thường.Sau đó kiểm tra xem assembly có được nạp hay không, nếu không - tạo ra mã stub (để biên dịch có thể, sau khi biên dịch chạy T4 một lần nữa, để tạo ra mã thực). Và có kiểm tra đơn vị có thể ngăn chặn mã gốc sẽ sản xuất.

0

Vì một lý do nào đó tôi không thể làm giải pháp @brian hoạt động được. Tôi kết thúc làm việc này Trong trường hợp của tôi, T4Generators là dự án riêng của tôi trong cùng một giải pháp.

<#@ assembly name="$(SolutionDir)\T4Generators\bin\Debug\T4Generators.dll" #> 
<#@ import Namespace="T4Generators" #> 
Các vấn đề liên quan