Making NotifyPropertyChanged refactorable.

By Mirek on (tags: INotifyPropertyChanged, categories: code)

Common problem when using INotifyPropertyChanged interface is that the PropertyChangedEventHandler event accept a string property name as a parameter. That cause a possible problem when we want to refactor the property and forget to update the provided property’s name.

There is a plenty of blog threads in the web that tries to solve this problem. The very common solution benefits from expression tree

protected void NotifyPropertyChanged(Expression<Func<object>> exp)
{
    if (PropertyChanged != null)
    {
        string name = "";
        MemberExpression body = exp.Body as MemberExpression;
        if (body == null)
        {
            UnaryExpression ubody = (UnaryExpression)exp.Body;
            body = ubody.Operand as MemberExpression;
            name = body.Member.Name;
        }
        else
        {
            name = body.Member.Name;
        }
        PropertyChanged(this, new PropertyChangedEventArgs(name));
    }
}

so you can then easilly do that

private string name;
public String Name
{
    get
    {
        return name;
    }
    set
    {
        name = value;
        NotifyPropertyChanged(() => Name);
    }
}

Refactoring the Name property will automatically update the expression provided in NotifyPropertyChanged call. This solution however has a performance issue. Simple test showed that it is about 50 times slower that standard string based call.

Since C# 5.0 we can benefit from CallerMemberAttribute which simply gives us the name of the calling method or property.

protected void NotifyChangedThis([CallerMemberName] string propertyName == null)
{
    if (PropertyChanged != null)
    {
        PropertyChanged(this, new PropertyChangedEventArgs(propertyName));
    }
}

Now we can simply write this

private string name;
public String Name
{
    get
    {
        return name;
    }
    set
    {
        name = value;
        NotifyChangedThis();
    }
}

And the name of the attribute is automatically resolved by the attribute. The performance of this approach is as good as the string based version. So this is what we all like: simple and good Puszczam oczko