CodeContracts로 InotifyPropertyChanged의 올바른 구현 시행 -“입증되지 않은 필요”

StackOverflow https://stackoverflow.com/questions/1621921

문제

PropertyChanged가 제기 될 때 InotifyPropertyChanged의 올바른 구현을 시행 할 수있는 쉬운 방법을 찾고 있습니다. 실제로 정의 된 속성을 참조해야합니다. Microsoft의 새로운 CodeContract 도구 로이 작업을 시도했지만 "CodeContracts : 입증되지 않은 경우"경고를 계속받습니다. 여기 내 코드가 있습니다 ...

public sealed class MyClass : INotifyPropertyChanged
{
    private int myProperty;
    public int MyProperty
    {
        get
        {
            return myProperty;
        }
        set
        {
            if (myProperty == value)
            {
                return;
            }

            myProperty = value;
            OnPropertyChanged("MyProperty");
        }
    }

    private void OnPropertyChanged(string propertyName)
    {
        Contract.Requires(GetType().GetProperties().Any(x => x.Name == propertyName));

        var handler = PropertyChanged;
        if (handler != null)
        {
            handler(this, new PropertyChangedEventArgs(propertyName));
        }
    }

    public event PropertyChangedEventHandler PropertyChanged;
}

어쨌든 이것을 작동시킬 수 있습니까?

도움이 되었습니까?

해결책

정적 분석 도구를 의미한다고 생각하십니까? (런타임 수표가 작동 할 것으로 예상됩니다. 그리고 아마도 디버그 빌드에 남겨 둘 수 있습니다). 나는 이것이 정적 분석이 볼 수있는 것임을 의심합니다. GetType().GetProperties() 단순히 너무 복잡합니다.

요컨대; 의심스러워 ... 람다 (Lambdas)Expression)는 옵션이지만 문자열을 통과하는 것보다 훨씬 느립니다.

다른 팁

우선,이 목적을 위해 나는 개인적으로 ObservableObject 구현을 사용합니다. MVVM 재단. 디버그 구축 전용 런타임 확인입니다.

public event PropertyChangedEventHandler PropertyChanged;

protected virtual void OnPropertyChanged(string propertyName)
{
    this.VerifyPropertyName(propertyName);

    PropertyChangedEventHandler handler = this.PropertyChanged;
    if (handler != null)
    {
        var e = new PropertyChangedEventArgs(propertyName);
        handler(this, e);
    }
}

[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 (this.ThrowOnInvalidPropertyName)
            throw new Exception(msg);
        else
            Debug.Fail(msg);
    }
}

아마도 가장 쉬운 방법 일지 모르지만 특정 단점이 있습니다. 일부 기본 클래스에서 물려받을 수 있어야합니다. 런타임에서만 작동합니다 (이것은 항상 WPF 경험에서 충분했지만)는 "패치"처럼 보입니다. 누락 된 정적 점검.

이 경우 정적 분석 / 정적 도구를 활성화하는 몇 가지 방법이 있습니다.

  1. Marc가 말한 것처럼 Lambda 표기법을 사용하고 런타임에 문자열을 추출하십시오.
  2. 사용자 정의 FXCOP 규칙을 작성하십시오.
  3. AOP 도구를 사용하여 코드를 후 처리하십시오 메타 마크 업과 함께.

Codecontracts의 경우, 정적 분석에서 이러한 종류의 점검을 처리하기에 충분히 성숙하지 않다고 생각합니다. 상상해보십시오. 람다를 구문 분석해야합니다. 잘못으로 실패 할 수있는 방법을 이해해야합니다. propertyName,이 방법에 대한 모든 호출을 찾아 가능한 모든 입력 등을 알아냅니다. 그것은 그러한 종류의 점검에 잘못된 도구 일뿐입니다.

내가 과거에 이것을했던 방식은 우리의 좋은 친구 람다를 사용하는 것입니다. 표현식을 사용하여 속성 자체를 OnPropertyChanges의 구현에 전달하고 발현 트리를 사용하여 속성을 추출 할 수 있습니다. 이를 통해 PropertyChanged 이벤트를 제기하는 회원의 컴파일 시간 점검을 제공합니다.

물론 표현의 사용은 전적으로 필요한 성능 유형에 달려 있습니다.

아래 코드 스 니펫을 참조하십시오.

using System;
using System.Linq;
using System.ComponentModel;
using System.Linq.Expressions;

namespace OnNotifyUsingLambda
{
    public class MainClass : INotifyPropertyChanged
    {
         public static void Main (string[] args) { new MainClass().Run();}
         public void Run()
         {
              this.PropertyChanged += (sender, e) => Console.WriteLine(e.PropertyName);
              MyProperty = "Hello";
         }

         private string myProperty;
         public string MyProperty  
         {
             get
             {
                 return myProperty;
             }
             set
             {
                 myProperty = value;
                 // call our OnPropertyChanged with our lamba expression, passing ourselves.
                 // voila compile time checking that we haven't messed up!
                 OnPropertyChanged(x => x.MyProperty); 
              }
         }  

         /// <summary>
         /// Fires the PropertyChanged for a property on our class.
         /// </summary>
         /// <param name="property">
         /// A <see cref="Expression<Func<MainClass, System.Object>>"/> that contains the 
         /// property we want to raise the event for.
         /// </param>
         private void OnPropertyChanged (Expression<Func<MainClass, object>> property)
         {
             // pull out the member expression (ie mainClass.MyProperty)
             var expr = (MemberExpression)property.Body; 

             if (PropertyChanged != null)
             {
                 // Extract everything after the period, which is our property name.
                 var propName = expr.ToString ().Split (new[] { '.' })[1];
                 PropertyChanged (this, new PropertyChangedEventArgs(propName));
             }
          }

          public event PropertyChangedEventHandler PropertyChanged;
     }
}
라이센스 : CC-BY-SA ~와 함께 속성
제휴하지 않습니다 StackOverflow
scroll top