فرض التنفيذ الصحيح INotifyPropertyChanged مع CodeContracts - "يتطلب غير مثبتة"

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

سؤال

أنا أبحث عن طريقة سهلة لفرض التنفيذ الصحيح INotifyPropertyChanged أيعندما PropertyChanged أثيرت يجب أن مرجع العقار الذي هو في الواقع تعريف.لقد حاولت فعل هذا مع 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. مثل مارك يقول ، استخدام امدا التدوين و استخراج الأوتار في وقت التشغيل.
  2. كتابة مخصص التقدم القاعدة.
  3. استخدام اوب أداة إلى ما بعد العملية البرمجية مع بعض ميتا العلامات.

أما بالنسبة 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