2010-06-03 14 views
10

Tôi hiện đang làm việc để thiết lập một dự án mới của tôi và tự hỏi làm thế nào tôi có thể đạt được rằng các lớp ViewModel của tôi có hỗ trợ INotifyPropertyChanged trong khi không phải tự tay mã hóa tất cả các thuộc tính.Thực thi INotifyPropertyChanged tự động thông qua việc tạo mã T4?

Tôi đã xem xét các khung công tác AOP nhưng tôi nghĩ rằng chúng sẽ làm nổ tung dự án của tôi với một sự phụ thuộc khác.

Vì vậy, tôi đã nghĩ đến việc tạo các cài đặt thuộc tính với T4.

Thiết lập sẽ là điều này: Tôi có một lớp ViewModel chỉ khai báo biến nền thuộc tính của nó và sau đó tôi sử dụng T4 để tạo ra các triển khai thuộc tính từ nó.

Ví dụ này sẽ là ViewModel của tôi:

public partial class ViewModel 
{ 
    private string p_SomeProperty; 
} 

Sau đó, T4 sẽ đi qua các tập tin nguồn và tìm kiếm khai báo thành viên mang tên "p_" và tạo ra một tập tin như thế này:

public partial class ViewModel 
{ 
    public string SomeProperty 
    { 
     get 
     { 
      return p_SomeProperty; 
     } 
     set 
     { 
      p_SomeProperty= value; 
      NotifyPropertyChanged("SomeProperty"); 
     } 
    } 
} 

Cách tiếp cận này có một số ưu điểm nhưng tôi không chắc liệu nó có thực sự hoạt động hay không. Vì vậy, tôi muốn đăng ý tưởng của tôi ở đây trên StackOverflow như một câu hỏi để có được một số phản hồi về nó và có thể một số lời khuyên làm thế nào nó có thể được thực hiện tốt hơn/dễ dàng hơn/an toàn hơn.

+2

Tôi cảm thấy như một moron, nhưng tôi không biết T4 là gì cho đến khi tôi googled nó vì câu hỏi này. Tôi không thể tin rằng điều này không được nói nhiều hơn nữa! – BFree

+0

Tôi cũng thế. Tôi đã ở đây từ chủ đề tiền xử lý C# tuổi (http://stackoverflow.com/questions/986404/does-a-c-preprocessing-tool-exist). Doh. – lo5

+0

xem thêm http://stackoverflow.com/questions/1315621/implementing-inotifypropertychanged-does-a-better-way-exist –

Trả lời

7

Here's a great post by Colin Eberhardt khi tạo Thuộc tính phụ thuộc từ T4 bằng cách kiểm tra thuộc tính tùy chỉnh trực tiếp từ Visual Studio với EnvDTE. Nó không phải là khó khăn để thích ứng với nó để kiểm tra các lĩnh vực và tạo mã một cách thích hợp kể từ khi bài có chứa phương pháp tiện ích đơn giản để duyệt các nút mã.

Lưu ý rằng khi sử dụng T4 từ VS, bạn không nên sử dụng Reflection trên hội đồng của riêng bạn hoặc họ sẽ bị khóa và bạn sẽ phải khởi động lại Visual Studio để xây dựng lại.

+0

Điều này thật ngọt ngào. Tôi đã điều chỉnh mẫu để làm điều tương tự với việc tạo ra các bộ mô tả kiểu tùy chỉnh. Đã lưu hàng nghìn dòng mã. – Will

+1

Lưu ý rằng như của VS2010 SP1, vấn đề khóa được giải quyết, do đó, phản ánh bây giờ là OK để sử dụng. – GarethJ

1

Nó chắc chắn sẽ hoạt động.

tôi khuyên bạn nên đầu tiên viết một lớp cơ sở mà thực hiện INotifyPropertyChanged, cho nó một phương pháp protected void OnPropertyChanged(string propertyName), làm cho nó bộ nhớ cache PropertyChangeEventArgs đối tượng của nó (một cho mỗi tên thuộc tính độc đáo - không có điểm trong việc tạo ra một đối tượng mới mỗi khi sự kiện này được nâng lên), và có lớp T4 tạo ra của bạn xuất phát từ cơ sở này.

Để có được các thành viên cần tính thực hiện, bạn chỉ có thể làm điều gì đó như:

BindingFlags flags = BindingFlags.Instance | BindingFlags.NonPublic; 
FieldInfo[] fieldsNeedingProperties = inputType.GetFields(flags) 
    .Where(f => f.Name.StartsWith("p_")) 
    .ToArray(); 

Và đi từ đó:

<# foreach (var field in fieldsNeedingProperties) { #> 
<# string propertyName = GetPropertyName(field.Name); #> 
    public <#= field.FieldType.FullName #> <#= propertyName #> { 
     get { return <#= field.Name #>; } 
     set { 
      <#= field.Name #> = value; 
      OnPropertyChanged("<#= propertyName #>"); 
     } 
    } 
<# } #> 

<#+ 
    private string GetPropertyName(string fieldName) { 
     return fieldName.Substring(2, fieldName.Length - 2); 
    } 
#> 

Và vân vân.

+0

Phản ánh tốt không thực sự là một lựa chọn (xem câu trả lời của Julien Lebosquain). – chrischu

+1

@chrischu: Nếu bạn nói như vậy. Dường như với tôi rằng việc loại trừ sự phản chiếu hoàn toàn là một chút quyết liệt đối với một cái gì đó mà chỉ cần được thực hiện một lần cho mỗi lớp. Tôi đã sử dụng kỹ thuật này nhiều lần trước đây để viết các lớp cho tôi khi tôi không cảm thấy như đang gõ quá nhiều. Vì vậy, bạn phải khởi động lại Visual Studio sau đó. Điều đó thật khủng khiếp phải không? –

+1

Lưu ý rằng như của VS2010 SP1, vấn đề về khóa được giải quyết. – GarethJ

3

Có rất nhiều cách để làm da mèo này.

Chúng tôi đã và đang đùa giỡn với PostSharp để nạp bản mẫu soạn sẵn INotifyProperty. Điều đó dường như hoạt động khá tốt.

Điều đó đang được nói, không có lý do gì khiến T4 không hoạt động.

Tôi đồng ý với Dan rằng bạn nên tạo triển khai lớp cơ sở của OnPropertyChanged.

Bạn đã xem xét việc chỉ sử dụng đoạn mã?Nó sẽ viết bản mẫu cho bạn. Nhược điểm duy nhất là nó sẽ không cập nhật tự động nếu bạn muốn thay đổi tên thuộc tính vào một số ngày sau đó.

<?xml version="1.0" encoding="utf-8" ?> 
<CodeSnippets xmlns="http://schemas.microsoft.com/VisualStudio/2005/CodeSnippet"> 
    <CodeSnippet Format="1.0.0"> 
    <Header> 
     <Title>propin</Title> 
     <Shortcut>propin</Shortcut> 
     <Description>Code snippet for property and backing field with support for INotifyProperty</Description> 
     <SnippetTypes> 
     <SnippetType>Expansion</SnippetType> 
     </SnippetTypes> 
    </Header> 
    <Snippet> 
     <Declarations> 
     <Literal> 
      <ID>type</ID> 
      <ToolTip>Property type</ToolTip> 
      <Default>int</Default> 
     </Literal> 
     <Literal> 
      <ID>property</ID> 
      <ToolTip>Property name</ToolTip> 
      <Default>MyProperty</Default> 
     </Literal> 
     </Declarations> 
     <Code Language="csharp"> 
     <![CDATA[private $type$ _$property$; 

    public $type$ $property$ 
    { 
     get { return _$property$;} 
     set 
    { 
     if (value != _$property$) 
     { 
     _$property$ = value; 
     OnPropertyChanged("$property$"); 
     } 
    } 
    } 
    $end$]]> 
     </Code> 
    </Snippet> 
    </CodeSnippet> 
</CodeSnippets> 
+0

Có, tôi đã xem xét sử dụng đoạn mã. Tuy nhiên bằng cách sử dụng đoạn mã vẫn còn cách làm việc nhiều hơn sau đó sử dụng T4 (khi nó cuối cùng hoạt động ..) Tôi nhìn PostSharp nhưng điều tôi không muốn phụ thuộc nhiều hơn vào dự án của mình. – chrischu

+0

Đó là sự thật. Nhưng, theo ý kiến ​​của tôi, chúng ta tiêu tốn rất nhiều năng lượng cho mô hình này, chỉ vì chúng ta ghét nó và nó xấu xí. Nhưng nó không phải là khó hiểu hoặc duy trì. Phải mất 5 giây để thêm một thuộc tính và bản mẫu soạn sẵn OnPropertyChanged. Vì vậy, những gì tốt hơn 2-3 dòng mã lặp đi lặp lại hoặc phụ thuộc vào PostSharp hoặc một số T4 obtuse? –

+0

2-3 dòng mã lặp lại cho mỗi thuộc tính. Điều đó tăng lên. Ngoài ra với mã được tạo ra mà làm cho OnPropertyChanged-gọi các vấn đề mà OnPropertyChanged ("SomeProperty") là không an toàn cho lỗi chính tả được tự động khắc phục mà không tham gia một hiệu suất thời gian chạy hit (như thông qua phản ánh). – chrischu