Erzwingen die korrekte Umsetzung der INotifyPropertyChanged mit CodeContracts - „erfordert nicht bewiesen“

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

Frage

Ich bin auf der Suche nach einer einfachen Möglichkeit, die korrekte Umsetzung von INotifyPropertyChanged das heißt zu erzwingen, wenn Property angehoben wird, muss eine Eigenschaft verweisen, die tatsächlich definiert ist. Ich habe versucht, diese mit den neuen CodeContract Tool von Microsoft zu tun, aber ich halte die Warnung bekommen „CodeContracts: erfordern nicht bewiesen“. Hier ist mein Code ...

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

Gibt es das überhaupt Arbeit zu bekommen?

War es hilfreich?

Lösung

Ich nehme an, Sie mit den statischen Analysetool bedeuten? (Ich würde erwarten, dass die Laufzeitüberprüfung zu arbeiten, zumindest - und man kann es vermutlich verlassen in Debug-Builds). Ich bezweifle, dass dies etwas ist, die statische Analyse zu durchschauen können, wird -. GetType().GetProperties() ist einfach zu komplex, etc

Kurz gesagt; Ich bezweifle es ... lambdas (Expression) sind eine Option, aber sie sind viel langsamer als nur einen String übergeben.

Andere Tipps

Ok, vor allem für diesen Zweck verwende ich persönlich ObservableObject Implementierung von der MVVM Stiftung . Es ist ein DEBUG-build nur fast identische Laufzeit überprüfen, um zu verkaufen.

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

Es ist wahrscheinlich der einfachste Weg, aber es hat einige Nachteile: Sie müssen von einer Basisklasse erben zu können, es funktioniert nur in Laufzeit (obwohl dies immer genug in meiner Wpf-Erfahrung war), es sieht sicher wie ein "Patch" für eine fehlende statische Überprüfung.

Sie haben mehr Möglichkeiten, statische Analyse / statische Werkzeuge für diesen Fall zu aktivieren:

  1. Wie Marc sagt: Verwendung Lambda-Notation und Extrakt String in der Laufzeit .
  2. schreiben eine benutzerdefinierte FxCop Regel .
  3. ein AOP-Tool verwenden, um Code mit einigen Meta-Auszeichnungs nachbearbeiten.

Wie bei dem CodeContracts, ich glaube, es ist noch nicht ausgereift genug, um diese Art von Kontrollen in der statischen Analyse zu behandeln. Stellen Sie sich vor, es hat Ihr Lambda zu analysieren, verstehen, wie es durch eine falsche propertyName versagt werden kann, um alle Anrufe zu dieser Methode finden, herauszufinden, alle möglichen Eingaben, etc. Es ist nur ein falsche Instrument für diese Art von Kontrolle.

So wie ich dies in der Vergangenheit getan haben, ist unser guter Freund Lambda zu verwenden. Durch die Verwendung von Ausdrücken können wir in den Eigenschaften selbst zu Ihrer Implementierung von OnPropertyChanges passieren, und verwenden Sie den Ausdrucksbaum, um die Eigenschaft zu extrahieren. Dies gibt Ihnen Zeit, die Überprüfung der Mitglieder kompilieren Sie das Property Ereignis heben für.

Natürlich Verwendung des Ausdrucks hängt ganz ab, welche Art von Leistung, die Sie benötigen.

Siehe Codeausschnitt unten:

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;
     }
}
Lizenziert unter: CC-BY-SA mit Zuschreibung
Nicht verbunden mit StackOverflow
scroll top