2012-10-29 21 views
8

Tôi có một thứ khá phức tạp được nhồi vào mẫu T4. Về cơ bản tôi có một cái gì đó giống nhưCó điều gì ngoài đó để làm cho mã T4 thêm ... sạch không?

{= foo =} văn bản hơn ...

và chuyển đổi nó thành một lớp (xem) như sau:

public class MyView 
{ 
    public string foo{get;set;} 
    public string Write() 
    { 
    return [email protected]" more text..."; 
    } 
} 

Các mã được tạo là tất nhiên phức tạp hơn nhiều so với điều này. Dù sao, mẫu T4 là hơn 600 dòng mã ngay bây giờ và thực sự trở thành không thể quản lý nhanh. Tôi tin rằng vấn đề chính là trộn mã và "nội dung" (tức là mã tĩnh). Tôi không thực sự chắc chắn làm thế nào để xóa sạch vấn đề này mặc dù (trong khi tất nhiên không ảnh hưởng đến mã được tạo ra). Tôi cũng không thấy bất kỳ cách khả thi nào để kiểm tra đơn vị mã T4 của tôi, ngoài việc thử nghiệm nó cho các lỗi thực thi T4. Và tất nhiên có vẻ là nhiệm vụ gần như không thể thử nghiệm của nó được tạo ra mã.

Có bất kỳ khung hoặc kỹ thuật loại "kiểu xem nào" mà tôi có thể sử dụng để làm cho mã mẫu T4 của tôi sạch hơn không?

+0

Đây có thể không phải là một tùy chọn, nhưng tôi thích [Resharper Templates] (http://www.jetbrains.com/resharper/features/code_templates.html) trên mẫu T4. Ngoài ra, [Resharper] (http://www.jetbrains.com/resharper/) cũng là một công cụ tuyệt vời cho các ứng dụng khác. Cũng đáng giá. – TylerOhlsen

+2

Resharper là một công cụ tốt, nhưng IMHO so sánh Resharper Templates với T4 là so sánh táo và cam. Mẫu Resharper đang quảng bá mẫu chống sao chép-dán với công cụ hỗ trợ dẫn đến ngày càng nhiều mã dự phòng mà bạn phải duy trì, do đó làm tăng chi phí bảo trì. T4 (và các công cụ khác) giảm thiểu dư thừa trong đó bạn viết một chương trình meta (có dự phòng thấp) tạo ra các tạo phẩm mã (với số lượng lớn redudancy). Điều quan trọng là kết nối thông thường giữa chương trình meta và mã được tạo sẽ không bị mất. – FuleSnabel

Trả lời

1

Sau một hành trình dài, cuối cùng tôi đã kiểm tra trong các bài kiểm tra đơn vị đầu tiên với các mẫu T4 của mình. Về cơ bản, những gì tôi đã làm là trừu tượng ra một "xem" (mẫu T4 thực tế), và "logic" (cái tạo mã, nhưng không thực sự xuất nó và không dựa vào T4)

I sau đó tiến thêm một bước nữa và sử dụng một số lớn hack để làm cho nó sao cho tệp logic của tôi biên dịch bên ngoài T4. Điều này có tác dụng tốt đẹp của việc làm cho nó để các lỗi intellisense và trình biên dịch làm việc. Nó cũng cho phép tôi truy cập vào lớp logic của tôi từ các bài kiểm tra đơn vị bằng cách đơn giản tham chiếu dự án.

Tôi đã viết một bài viết hoàn chỉnh với các ví dụ mã (trước/sau) và các bài kiểm tra đơn vị ví dụ on my blog, nếu bạn muốn các chi tiết dài về cách thực hiện.

5

IMHO hai khái niệm quan trọng nhất khi viết các mẫu phức tạp là

  1. Tách mô hình và quan điểm - Điều này giúp giữ cho mẫu logic để tối thiểu (thường là một nguyên nhân của vấn đề bảo trì). Cá nhân tôi không nghĩ rằng điều này đòi hỏi một khuôn khổ, nó chỉ yêu cầu bạn làm điều đó.
  2. Một phần là bạn của bạn - Tôi sử dụng T4 nói chung để tạo mã khung sườn từ mô hình. Hành vi cụ thể có thể không có giá trị nỗ lực để đưa vào mô hình, tốt hơn thường xuyên để cho phép hành vi đó đi vào thông qua việc sử dụng các lớp hoặc các phương thức một phần.

Không quan trọng nhưng thoải mái

  1. Hãy mã tìm kiếm - Tôi không dựa vào T4 Addons vì tôi thấy không ai trong số họ đủ tốt, với việc thiếu IntelliSense để điều hướng mã tôi phải làm cho mã có thể tìm kiếm được. Nó có thể đơn giản như thay vì gọi một thuộc tính Column Name, tôi gọi nó là ColumnName.
  2. Chèn "thẻ" vào đầu ra - Giúp dễ dàng tìm mã đã tạo ra phần đó của đầu ra.

Ví dụ tách mô hình/xem:

<# 
    // Model for Dependency Pooperties 
    Model = new [] 
    { 
     new ClassDefinition ("MyDataGrid") 
      { 
       P ("CultureInfo"   , "CultureInfo"), 
       P ("Pen"     , "CellBorderPen"), 
       P ("IEnumerable<object>" , "Rows"), 
       C ("WColumnDefinition"  , "Columns"), 
      }, 
    }; 
#> 
// Include the view 
<#@ include file="..\T4\DependencyProperties.ttinclude" #> 

Quan điểm sau đó lặp trên mô hình và tạo ra các thuộc tính phụ thuộc.

Hành vi của các thuộc tính phụ thuộc này sau đó được thực hiện như phương pháp phần

partial void Changed_Columns(
     ObservableCollection<WColumnDefinition> oldValue, 
     ObservableCollection<WColumnDefinition> newValue 
     ) 
    { 
     HookUpColumns(oldValue, null); 
     HookUpColumns(newValue, this);    
    } 

Lưu ý rằng việc đưa hành vi cụ thể này vào mô hình sẽ phức tạp đáng kể mô hình.

Cuối cùng; phải mất thời gian ngay cả đối với một lập trình viên có thẩm quyền để viết metaprograms một cách thành thạo.Nó đã cho tôi một số nỗ lực trước khi tôi đến một phong cách mà tôi tin là duy trì được nhưng đối với tôi nó là giá trị nỗ lực vì tôi có thể vận chuyển chất lượng nhanh hơn.

Tôi hy vọng điều này sẽ giúp ...

PS. Tôi không nghĩ rằng bất cứ ai sẽ tranh luận T4 là bao giờ thanh lịch nhưng nó darn hữu ích dù sao.

+0

Tôi đã thực sự xem xét việc tách "mô hình" ra thành một hội đồng thường xuyên và chỉ có một cái nhìn đơn giản "T4" thực sự xử lý việc tạo mã và sau đó có liên kết mã T4 đến assembly thường xuyên .. Điều này cũng giải quyết phần lớn các biến chứng thử nghiệm đơn vị – Earlz

+0

Ok, tôi nghĩ rằng tôi đã tìm ra cách "tốt" để thử nghiệm đơn vị ít nhất, điều này cũng buộc phải tách biệt nghiêm ngặt "chế độ xem" và "mô hình". Tôi sẽ đăng ở đây khi tôi nhận được tất cả các chi tiết được sắp xếp, nhưng về cơ bản nó liên quan đến việc có "mô hình" trong một tệp '.cs' khác được đưa vào đầu ra T4 được tạo ra. Nó không hoàn hảo, nhưng nó là tốt nhất tôi đã tìm thấy cho đến nay – Earlz

+1

Bạn có thể muốn xem [tự trả lời] của tôi (http://stackoverflow.com/a/13486081/69742) cho cách tôi đã kết thúc việc này, làm cho intellisense, lỗi trình biên dịch, và kiểm tra đơn vị làm việc trên logic được sử dụng bởi mẫu T4 của tôi – Earlz