INotifyPropertyChanged Implementation for VS2012

I told some folks at the East Tennessee .NET UG (ETNUG, which was adorably put on the reservation board at the after meeting bar as “Eatnug”) meeting in Knoxville that I would post info on a .NET 4.5 version of INotifyPropertyChanged that used CallerMemberName. I also said I wanted to reference other people rather than making up on my own because I’d rather post something already vetted.


CallerMemberName is a new feature of .NET 4.5 that lets you access the name of the thing that called the current method. It’s implemented by adding an attribute on an optional parameter:


public void Foo([CallerMemberName] string callerMemberName = null)


The CallerMemberName attribute signals that the caller parameter should contain the name of the calling method, to be filled in automatically if the calling code doesn’t pass a value. Since it’s an optional value, the calling code doesn’t need to pass a value, and should only pass one when chaining the “real” caller member name. Unfortunately, Intellisense doesn’t help you out here, so a really good parameter name, consistent across your project or organization is a great idea: I like callerMemberName as a direct indicator of the purpose/usage of the parameter.


There are a couple of obvious places to use CallerMemberName – logging and implementing INotifyPropertyChanged.


I asked on Twitter and checked around the Internet, and there are a bunch of simple examples that illustrate CallerMemberName. Here’s one in English, and one in Hungarian. There’s also a version in the documentation for the INotifyProertyChanged interface. If you’re interested in how CallerMemberName works, check these out.


If you’re interested in a bang-up, super-great, sea-salt and malt vinegar (potato chip) version, check out Dan Rigby’s blog posts here and especially here where he evaluates versions of INotifyPropertyChanged that have been used elsewhere. The basics are that the Set method should contain exactly one method call, the event should not be raised unless the property is actually changed to a new value, no strings should be used to avoid typo bugs, and no reflection or callstack access should be used to maintain performance.


I really like the flow of information on the Internet when people find something good and add to it. I have two enhancements I want to add – I hate having SetProperty in every class and I didn’t find a VB version.


First, you can use a common base class to avoid redundant SetProperty methods. This simplifies the data class. Note that it’s common to supply a protected OnPropertyChanged method in a base class. If this is called from something other than the property, such as the SetProperty method, the CallerMemberName can be passed in, passing on or chaining the original property name:


 


public class Foo : FooBase
 {
     private int _bar;
     public int Bar
     {
         get { return _bar; }
         set { SetProperty(ref _bar, value); }
     }
 }

 public abstract class FooBase : INotifyPropertyChanged
 {
     public event PropertyChangedEventHandler PropertyChanged;

     protected bool SetProperty<T>(
             ref T storage, T value,
         [CallerMemberName] String callerMemberName = null)
     {
         if (object.Equals(storage, value)) return false;

         storage = value;
         this.OnPropertyChanged(callerMemberName);
         return true;
     }

     protected void OnPropertyChanged(
             [CallerMemberName] string callerMemberName = null)
     {
         var eventHandler = this.PropertyChanged;
         if (eventHandler != null)
         {
             eventHandler(this,
                  new PropertyChangedEventArgs(callerMemberName));
         }
     }
 }


Since I didn’t find this available in VB, I translated:


Public Class Foo
    Inherits FooBase

    Private _bar As Integer
    Public Property Bar As Integer
        Get
            Return _bar
        End Get
        Set(value As Integer)
            SetProperty(_bar, value)
        End Set
    End Property

End Class

Public Class FooBase
    Implements INotifyPropertyChanged

    Public Event PropertyChanged(sender As Object, e As PropertyChangedEventArgs) _
            Implements INotifyPropertyChanged.PropertyChanged

    Protected Function SetProperty(Of T)(ByRef field As T, value As T,
                    <CallerMemberName> Optional callerMemberName As String = Nothing) _
                    As Boolean
        If Object.Equals(field, value) Then Return False

        OnPropertyChanged(callerMemberName)
        field = value
        Return True
    End Function

    Protected Sub OnPropertyChanged(
                    <CallerMemberName> Optional callerMemberName As String = Nothing)
        RaiseEvent PropertyChanged(Me, New PropertyChangedEventArgs(callerMemberName))
    End Sub

End Class