2009-11-02 5 views
1

WPF를 사용하면 INotifyPropertyChanged의 팬이되었습니다. 표현식을 사용하는 헬퍼를 사용하고 이름을 문자열로 반환합니다 (아래 예제 코드 참조). 그러나 매우 숙련 된 프로그래머가 볼 수있는 많은 응용 프로그램에서 원시 문자열을 처리하는 코드가 있습니다 (아래의 두 번째 예제 참조). 능숙하게는 표현을 사용하는 방법을 알고있는 MVP 유형을 의미합니다..net propertychange 알림 처리기 - 문자열 대 표현

내게있어, 쉬운 리팩터링 외에도 컴파일러가 실수를 포착 할 기회는 익스 프레스 접근법을 개선합니다. 제가 실종 된 원시 문자열을 사용하는 것에 대한 논쟁이 있습니까?

건배, Berryl

표현 도우미 예 : (일부 ViewModelBase 형 클래스)

public static string GetPropertyName<T>(Expression<Func<T, object>> propertyExpression) 
    { 
     Check.RequireNotNull<object>(propertyExpression, "propertyExpression"); 
     switch (propertyExpression.Body.NodeType) 
     { 
      case ExpressionType.MemberAccess: 
       return (propertyExpression.Body as MemberExpression).Member.Name; 
      case ExpressionType.Convert: 
       return ((propertyExpression.Body as UnaryExpression).Operand as MemberExpression).Member.Name; 
     } 
     var msg = string.Format("Expression NodeType: '{0}' does not refer to a property and is therefore not supported", 
      propertyExpression.Body.NodeType); 
     Check.Require(false, msg); 
     throw new InvalidOperationException(msg); 
    } 

원시 문자열 예제 코드 :

나에게
 /// <summary> 
    /// Warns the developer if this object does not have 
    /// a public property with the specified name. This 
    /// method does not exist in a Release build. 
    /// </summary> 
    [Conditional("DEBUG"), DebuggerStepThrough] 

    public void VerifyPropertyName(string propertyName) { 
     // Verify that the property name matches a real, 
     // public, instance property on this object. 
     if (TypeDescriptor.GetProperties(this)[propertyName] == null) { 
      string msg = "Invalid property name: " + propertyName; 

      if (ThrowOnInvalidPropertyName) throw new Exception(msg); 
      else Debug.Fail(msg); 
     } 
    } 

    /// <summary> 
    /// Returns whether an exception is thrown, or if a Debug.Fail() is used 
    /// when an invalid property name is passed to the VerifyPropertyName method. 
    /// The default value is false, but subclasses used by unit tests might 
    /// override this property's getter to return true. 
    /// </summary> 
    protected virtual bool ThrowOnInvalidPropertyName { get; private set; } 

답변

1

내가 예상했던 것보다 더 많은 시간을 보냈지 만 안전/재생 가능성과 성능이 좋은 솔루션을 찾았습니다. 좋은 배경 읽기 및 반사를 사용하는 대체 솔루션은 here입니다. Sacha Barber의 솔루션이 더 좋음 (배경 here)

아이디어는 변경 알림에 참여할 속성에 대해 표현 도우미를 사용하지만보기에 결과 PropertyChangedEventArgs를 저장하여 히트를 한 번만 가져 오는 것입니다. 모델.예를 들어 :

private static PropertyChangedEventArgs mobilePhoneNumberChangeArgs = 
     ObservableHelper.CreateArgs<CustomerModel>(x => x.MobilePhoneNumber); 

HTH,
Berryl

4

, 기회에 대한 컴파일러가 쉬운 리팩토링에 덧붙여 실수를 포착하면 익스 프레스 접근법이 개선됩니다. 제가 실종 된 원시 문자열을 사용하는 것에 대한 논쟁이 있습니까?

대부분의 경우 내 자신의 코드에서 표현 방식을 사용하고 개인적으로 동의합니다.

그러나,이를 방지하기 위해 내가 알고있는 두 가지 이유가 있습니다 :

  1. 그것은 특히 경험이 적은 .NET 개발자, 덜 분명. RaisePropertyChanged(() => this.MyProperty); 작성은 RaisePropertyChanged("MyProperty");과 같이 항상 사람에게 명백하지 않으며 프레임 워크 샘플과 일치하지 않습니다.

  2. 표현식을 사용할 때 약간의 성능 오버 헤드가 있습니다. 개인적으로, 이것이 실제로 그 이유가 의미심장하다고 생각하지는 않습니다. 왜냐하면 이것은 대개 리플렉션 사용으로 인해 느린 데이터 바인딩 시나리오에서 일반적으로 사용되기 때문에 그렇지만 잠재적으로 유효한 관심사입니다.

2

TypeDescriptor 방식을 사용할 때의 이점은 구현이 효율적으로 기재되고있는 타입 즉시 동적 특성 메타 데이터를 생성 할 수은 ICustomTypeDescriptor 구현에 기초하여 동적 속성 시나리오를 가능하게한다는 것이다. "속성"이 예를 들어 채워지는 결과 집합에 의해 결정되는 데이터 집합을 생각해보십시오.

문자열 대신 실제 형식 정보 (좋은 점)를 기반으로하기 때문에 표현식에서는 제공하지 않습니다.

+0

입니까? – Berryl

+0

오, 알겠습니다. 내가 직접 제공 한 코드 샘플에서 볼 수있다 :-) – Berryl

+0

그래, 기본적으로 표현 자체로 평면으로 떨어지는 리플렉션 자체를 수행하는 대신, 실제로 더 많은 힘을 가지며 확장 성을 제공하는 TypeDescriptor 아키텍처를 사용한다. 얘기 했어. 당연히 이는 약간의 오버 헤드가 있습니다. –

0

CallerMemberName 속성은이 속성에만 선택적 문자열 매개 변수에 부착 될 수 있으며, 매개 변수가 함수 호출에 발신자가 사용되지 않은 경우에는 발신자의 이름이 전달됩니다 4.5 .NET 에 도입 된 참조 문자열 매개 변수

이렇게하면 PropertyChanged 이벤트를 발생시킬 때 속성 이름을 지정할 필요가 없어 지므로 리팩터링과 함께 작동하며 변경 사항이 컴파일 타임에 수행되므로 성능에 차이가 없기 때문에이 이름을 사용하십시오. 다음은

는 TypeDescriptor를 내가 원시 문자열을 호출, 또는 제 3의 대안 해요 것과 같은 접근하는 http://msdn.microsoft.com/en-us/library/system.runtime.compilerservices.callermembernameattribute.aspx에서 찾을 수 있습니다 구현 및 추가 정보를 원하시면의 예와 http://msdn.microsoft.com/en-us/library/hh534540.aspx

public class DemoCustomer : INotifyPropertyChanged 
    { 
     string _customerName 
     public string CustomerName 
     { 
      get { return _customerNameValue;} 
      set 
      { 
       if (value != _customerNameValue) 
       { 
        _customerNameValue = value; 
        NotifyPropertyChanged(); 
       } 
      } 
     } 
     public event PropertyChangedEventHandler PropertyChanged; 
     private void NotifyPropertyChanged([CallerMemberName] String propertyName = "") 
     { 
      if (PropertyChanged != null) 
      { 
       PropertyChanged(this, new PropertyChangedEventArgs(propertyName)); 
      } 
     } 
    }