INotifyPropertyChanged – propertyName – Past, Present and Hopes for the Future

, , ,

Raising an INotifyPropertyChanged event requires a string containing the affected property’s name. Developers want a simple, clean and performance-efficient way to populate this string. New versions of .Net have brought developers closer and closer to achieving this goal.

Let’s review how INotifyPropertyChanged implementation options have improved over the years. Then, let’s consider an idea on how these options might be made even better.

Past

Back in .Net’s early days, property name strings were usually hard-coded by hand.

class DataObject : INotifyPropertyChanged
{
    private string name;
    public string Name
    {
        get { return name; }
        set
        {
            name = value;
            AnnouncePropertyChange("Name");
        }
    }

    private void AnnouncePropertyChange(string propertyName)
    {
        PropertyChangedEventArgs toAnnounce = new PropertyChangedEventArgs(propertyName);
        // Raise the event....
    }
    // ....
}

Hard-coded strings aren’t compiler checked for accuracy. Mismatches between the string’s contents and the related property’s name could easily occur.

The alternative to hand-specifying the string’s value, reflection, had the downside of introducing run-time overhead.

Expression Trees

.Net 3.5’s introduction of Linq and lambdas provided a way to specify the changed property’s name without relying on either hand-coded strings or run-time reflection. Instead, the property name could be specified in a lambda expression which would be converted into an Expression. As a lambda is code, its content is checked by the compiler which will error if a non-existent property name is referenced.

    public string Name
    {
        get { return name; }
        set
        {
            name = value;
            AnnouncePropertyChange(() => Name);
        }
    }

    protected void AnnouncePropertyChange<T>(Expression<Func<T>> expression)
    {
        var member = (expression.Body as MemberExpression);
        var property = (member.Member as PropertyInfo);
        PropertyChangedEventArgs toAnnounce = new PropertyChangedEventArgs(property.Name);

        // Raise the event....
    }

This improvement greatly reduced spelling-related errors. However, specifying the property’s name was still required. Ideally, there would be an easy way to infer this information.

Present

 CallerMemberNameAttribute

Starting in .Net 4.5, the compiler will insert the calling member’s name into a method’s string argument if that argument is marked with [CallerMemberName] and has a default value. Putting this functionality to work allows the name of the changed property to be inferred, eliminating the need to specify it via a lambda expression or hand-coded string.

    public string Name
    {
        get { return name; }
        set
        {
            name = value;
            AnnouncePropertyChange();
        }
    }

    private void AnnouncePropertyChange([CallerMemberName] string propertyName = "")
    {
        PropertyChangedEventArgs toAnnounce = new PropertyChangedEventArgs(propertyName);
        // Raise event....
    }

Hopes for the Future

.Net’s feature improvements have reduced the potential for errors involved with implementing INotifyPropertyChanged by eliminating the need to specify the changed property’s name. However, a lot of boilerplate code is still required. This verbosity distracts from the purpose of the class and provides places for bugs to hide.

A data-carrying class that doesn’t implement INotifyPropertyChanged can have beautiful simplicity because it doesn’t need to be cluttered with repetitious plumbing code:

class DataObject
{
    public string Name { get; set; }
    public DateTime BirthDate { get; set; }
}

My hope is that a future version of C#/.Net will allow this same simplicity to be achieved in classes that implement INotifyPropertyChanged.

This could be achieved if C#/.Net would provide a way to modify the property auto-implementation code generation process (the process by which the compiler converts “{ get;  set; }” into actual getter/setter code).

The compiler would be signaled to use a custom generator by a class- or method-scoped attribute that inherited from a specific base class. The custom attribute would contain the necessary plumbing to point the compiler to the actual custom auto-generation engine.

This approach would put the developer in complete control over the auto-generation process, allowing him to expand it to include an INotifyPropertyChanged implementation and beyond.

Leave a Reply

Your email address will not be published. Required fields are marked *