INotifyPropertyChanged (2 of 3) – without the backing fields

10
April 6, 2013 // wpf

Welcome back for part 2 in this INotifyPropertyChanged series. This time we’ll be taking a look at the backing fields that are a common smell to this pattern.

Backing fields

To prevent raising notifications when a property is not really changing, it is very common to check the new value against the old. This means we have to save the old value somewhere and the easiest way to do that is with a matching backing field.

        private int _iterations;

        public int Iterations
        {
            get { return _iterations; }
            set
            {
                if (_iterations != value)
                {
                    _iterations = value;
                    OnPropertyChanged();
                }
            }
        }

It works, but it smells of redundancy especially since we usually don’t use that backing field anywhere else. If only we could store the property’s value somewhere else…

Backing dictionary

Instead of a backing field behind every individual property, we can create a single backing dictionary to cover all of our properties. We’ll also create a couple helper methods for getting and setting property values.

        private readonly Dictionary<string, object> _propertyBackingDictionary = new Dictionary<string, object>();

        protected T GetPropertyValue<T>([CallerMemberName] string propertyName = null)
        {
            if (propertyName == null) throw new ArgumentNullException("propertyName");

            object value;
            if (_propertyBackingDictionary.TryGetValue(propertyName, out value))
            {
                return (T)value;
            }

            return default(T);
        }

        protected bool SetPropertyValue<T>(T newValue, [CallerMemberName] string propertyName = null)
        {
            if (propertyName == null) throw new ArgumentNullException("propertyName");

            if (EqualityComparer<T>.Default.Equals(newValue, GetPropertyValue<T>(propertyName))) return false;

            _propertyBackingDictionary[propertyName] = newValue;
            OnPropertyChanged(propertyName);
            return true;
        }

This code encapsulates both the equality comparisons and storing/retrieving the values in a tidy fashion that we can promote up to a base class and only have defined once.

Now for the candy, here’s what our property looks like after:

        public int Iterations
        {
            get { return GetPropertyValue<int>(); }
            set { SetPropertyValue(value); }
        }

No more backing fields, and we’ve more than halved the amount of code we have to write! If you’re bouncing in your chair in excitement now – don’t worry you’re not alone. 😉

Credit for the idea goes to Bas Hamer who mentioned the idea in a comment on Jesse Liberty’s C# 5 – Making INotifyPropertyChanged Easier post.

Note that calling SetPropertyValue will return a boolean indicating if the value has changed or not. You can use this to perform additional work when the property has changed. A typical use is notifying other dependent properties, but we’re going to take care of that too in the next part of this series.

Performance

Same as last time, how do these approaches compare in performance? I’ve modified the sample application (attached) that raises a million notifications using both mechanisms. Here’s the results:

Performance image

Performance comparison between backing field based and backing dictionary based mechanisms.


Our backing field baseline took 4.805s to raise a million notifications. Using a backing dictionary took 5.327s to do the same, meaning only about a 10% hit for the extra work which is very modest and well worth the code cleanup in my opinion.

Summary

With a backing dictionary in a base class, we can cut out a lot of redundant code without a noticeable performance penalty. Stay tuned for the next part in the series, where we’ll get rid of reversed notifications.

Code: SteveCadwallader.NotifyPropertyChanged.2of3.zip

Part 1: INotifyPropertyChanged (1 of 3) – without the strings
Part 3: INotifyPropertyChanged (3 of 3) – without the reversed notifications

About the author

Steve Cadwallader is a software developer who geeks out on user interfaces, clean code and making things easier.

10 Comments

  1. Cameron MacFarland April 7, 2013 at 7:45 pm Reply

    You might want to check out https://github.com/fody/propertychanged. It uses AOP to weave in property change notification after compilation.

    Using it all properties can just be written as auto-properties, making all the extra code redundant. And I always like less code.

  2. Very nice! It would be even better to not have to specify the type in the call to GetPropertyValue. Any ideas about how to do that?

    • Thanks. 🙂

      I agree, that would be nice to cut out having to pass the type to GetPropertyValue. I was considering storing the type in the dictionary, but the return type of GetPropertyValue would have to be a generic object in that case which still leaves us stuck with a cast on the outside which is no better.

  3. Hello, I suppose there are should be a little modification in GetPropertyValue method:
    Object value;
    if (_propertyBackingDictionary.TryGetValue(propertyName, out value))
    {
    return Equals(value, default(T)) ? default(T) : (T)value;
    }
    return default(T);
    because if value equal is to null, (T)value throws NullReferenceException.

  4. I like this solution.. however there are certain scenarios where it doesn’t quite work out. There are cases where you wanna check for ReferenceEquality and there are other cases where you wanna check for DataEquality(Equals). There are also cases where you wanna modify a Property without notifying the GUI, in this case you have to modify the local member so that you can do the Notifying later or leave it out at all. Just keep that in mind while using this solution 🙂

  5. Hi, This is cool solution!
    I have one idea to avoid to specify the type in the call to GetPropertyValue.
    I added override of GetPropertyValue().

    “`
    //baseclass
    protected T GetPropertyValue([CallerMemberName]string propertyName = null)
    return GetPropertyValue(default(T), propertyName);

    protected T GetPropertyValue(T initialValue, [CallerMemberName]string propertyName = null)

    //each property
    get { return GetPropertyValue(initialValue: 123); }
    “`

    What do you think?

    • Thanks for sharing the idea! I think that will work for value types, but for reference types which default to null you’d still have to explicitly provide the class type via a cast on the initial value (e.g. GetPropertyValue((MyClass)null). It looks useful though if you’re typically using value types and not wanting to default to 0. 🙂

Leave a Comment