2010-06-03 3 views
10

현재 내 새 프로젝트를 설정하고 있는데 모든 ViewModel 클래스가 INotifyPropertyChanged를 지원하고 모든 속성을 직접 처리 할 필요가 없다는 것을 어떻게 달성 할 수 있었는지 궁금합니다.T4 코드 생성을 통한 자동 INotifyPropertyChanged 구현?

AOP 프레임 워크를 살펴 보았지만 프로젝트가 다른 종속성으로 인해 날려 버릴 것이라고 생각합니다.

그래서 T4를 사용하여 속성 구현을 생성하는 방법에 대해 생각했습니다.

설정은 다음과 같습니다. ViewModel 클래스에 속성 배경 변수 만 선언하고 T4를 사용하여 속성 구현을 생성합니다.

예를 들어이 내 뷰 모델이 될 것입니다 :

public partial class ViewModel 
{ 
    private string p_SomeProperty; 
} 

그런 다음 T4 소스 파일 가서 "P_"라는 멤버 선언에 대한보고이 같은 파일을 생성 할 :

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

을 이 접근법에는 몇 가지 장점이 있지만 실제로 작동하는지 확실하지 않습니다. 그래서 StackOverflow에 아이디어를 게시하고 여기에 대한 피드백을 얻고 좀 더 좋고/더 쉽고/더 안전하게 할 수있는 조언을하기를 원했습니다.

+2

나는이 질문 때문에 나는 단지 그것을봤을 때까지 나는 T4가 뭔지 전혀 몰랐다. 나는 이것에 대해 더 이상 말하지 않는다고 믿을 수 없다! – BFree

+0

나도. 나는 오래된 C# 전 처리기 스레드 (http://stackoverflow.com/questions/986404/does-a-c-preprocessing-tool-exist)에서 왔습니다. 도. – lo5

+0

또한보십시오 http://stackoverflow.com/questions/1315621/implementing-inotifypropertychanged-does-a-better-way-exist –

답변

7

Here's a great post by Colin Eberhardt EnvDTE를 사용하여 Visual Studio에서 직접 사용자 지정 특성을 검사하여 T4의 종속성 속성 생성시. 이 게시물에는 코드 노드를 탐색하는 간단한 유틸리티 메소드가 포함되어 있으므로 필드를 검사하고 코드를 적절하게 생성하기 위해이를 적용하는 것이 어렵지 않아야합니다.

VS에서 T4를 사용할 때 자신의 어셈블리에서 Reflection을 사용하지 않아야합니다. 그렇지 않으면 다시 고정되므로 Visual Studio를 다시 시작해야만 다시 빌드해야합니다.

+0

이것은 달콤했다. 필자는 사용자 지정 형식 설명자를 생성하는 것과 동일한 작업을 수행하기 위해 템플릿을 수정했습니다. 말 그대로 수천 줄의 코드가 저장되었습니다. – Will

+1

VS2010 SP1의 경우 잠금 문제가 해결되었으므로 이제 반영을 사용할 수 있습니다. – GarethJ

1

확실히 작동해야합니다.

나는 그것의 PropertyChangeEventArgs 오브젝트 (고유 한 속성 이름 당 하나의 캐시 만들고, 그것을 protected void OnPropertyChanged(string propertyName) 방법을 제공 INotifyPropertyChanged를 구현하는 기본 클래스를 작성하지 첫째 권 해드립니다 - 이벤트가 발생할 새로운 객체를 매번 생성에 어떤 점을), T4 생성 클래스를이 기본 클래스에서 파생시킵니다.

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

그리고 거기에서 이동 : 등등

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

은 그냥 뭔가를 할 수있는, 속성이 구현해야 할 구성원을 얻으려면.

+0

글쎄요, 반사는 실제로 옵션이 아닙니다. (Julien Lebosquain의 답변을보십시오). – chrischu

+1

@chrischu : 그렇게 말하면. 반성을 완전히 배제하는 것은 수업 당 한 번만하면되는 일에 조금 과감한 것으로 보인다. 나는이 기술을 여러 번 사용하여 수업을 작성했으며 많은 타이핑을하고 싶지 않았습니다. 따라서 나중에 Visual Studio를 다시 시작해야합니다. 그렇게 끔찍한가요? –

+1

VS2010 SP1부터 잠금 문제가 해결되었습니다. – GarethJ

3

이 고양이를 피하는 데는 여러 가지 방법이 있습니다.

우리는 PostSharp를 사용해 INotifyProperty 상용구를 삽입하고 있습니다. 그건 꽤 잘하는 것 같습니다.

그렇다고해서 T4가 작동하지 않는 이유는 없습니다.

저는 OnPropertyChanged의 기본 클래스 구현을 생성해야한다는 Dan에 동의합니다.

코드 스 니펫을 사용해 본 적이 있습니까?그것은 당신을 위해 상용구를 쓸 것입니다. 유일한 단점은 나중에 속성 이름을 변경하려는 경우 자동으로 업데이트되지 않는다는 것입니다.

<?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

예, 코드 스 니펫 사용을 고려했습니다. 그러나 코드 스 니펫을 사용하는 방법은 T4를 사용하는 것보다 훨씬 더 효과적입니다. (마침내 작동합니다.) PostSharp를 보았습니다.하지만 그 프로젝트에서 더 이상 의존성을 갖고 싶지는 않습니다. – chrischu

+0

사실입니다. 그러나 제 의견으로는이 패턴에 많은 에너지를 소비합니다. 단지 우리가 그것을 싫어하고 추악하기 때문입니다. 그러나 이해하거나 유지하기가 어렵지 않습니다. 속성과 OnPropertyChanged 상용구를 추가하는 데 5 초가 걸립니다. 그렇다면 2-3 줄의 반복적 인 코드 나 PostSharp 또는 무뚝뚝한 T4에 대한 의존성이 더 좋을까요? –

+0

속성 당 반복 코드가 2 ~ 3 줄입니다. 그것은 합산한다. 또한 OnPropertyChanged - OnPropertyChanged ("SomeProperty")가 맞춤법 오류에 대해 안전하지 않은 문제를 호출하는 생성 된 코드는 런타임 성능 저하 (예 : 리플렉션)없이 자동으로 해결됩니다. – chrischu