Click here to Skip to main content
Click here to Skip to main content

CallMemberName – An easier way to do INotifyPropertyChanged and more

By , 27 Aug 2012
 

In WPF, when applying the MVVM (an architectural pattern) we often need to implement the INotifyPropertyChanged on certain classes (ViewModel classes), which means something like this:

public class PersonViewModel : INotifyPropertyChanged
{
    private string _name;
    public string Name
    {
        get { return _name; }
        set
        {
            if (_name == value) return;
            _name = value;
            NotifyPropertyChanged("Name");
        }
    }

    private void NotifyPropertyChanged(string propertyName)
    {
        var evt = PropertyChanged;
        if (evt != null) evt(this, new PropertyChangedEventArgs(propertyName));
    }

    public event PropertyChangedEventHandler PropertyChanged;
}

In case you’re wondering why I copied the PropertyChanged value to the local variable called “evt” and then tested it for null is that you can have race conditions, in general, triggering events (i.e.: you test the attribute value, it is not null and before you trigger it some other thread sets it to null and bang, NullReferenceException when you trigger it). More details on this CodeProject.

The next step is to pull the NotifyPropertyChanged method and PropertyChanged event into a base class (let’s call it ViewModelBase) and you’ve eliminated redundancy between several ViewModel classes.

The not-so-nice part is having the call to NotifyPropertyChanged stringly-typed. That means that if later you rename (via Visual Studio or ReSharper) the Name property to “FullName” the call will still pass “Name” as the argument.

Some blog posts around the web show how you can use a Func to make it type-safe (refactor safe etc).

More or less they’re doing the same thing :

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

    protected void NotifyPropertyChanged(Expression<Func<object>> propertyAccessor)
    {
        var evt = PropertyChanged;
        if (evt == null) return;
        var propertyName = propertyAccessor.GetName();
        evt(this, new PropertyChangedEventArgs(propertyName));
    }
}

public static class Utils
{
    public static string GetName(this LambdaExpression expression)
    {
        MemberExpression memberExpression;
        if (expression.Body is UnaryExpression)
        {
            var unaryExpression = (UnaryExpression)expression.Body;
            memberExpression = (MemberExpression)unaryExpression.Operand;
        }
        else if (expression.Body is MemberExpression)
        {
            memberExpression = (MemberExpression)expression.Body;
        }
        else
        {
            return null;
        }
        return memberExpression.Member.Name;
    }
}

This is definitely nicer, not-redundant and type-safe. It does have the drawback of having some runtime performance penalty associated with the reflection of the expression. You could cache the property name string in a private field but then you’d have to write more code in the ViewModel classes which would… suck. In practice this performance penalty is negligible so you can just ignore this.

Then came .NET 4.5 and among other improvements a new mechanism has been introduced : CallMemberName.

Historically some folks tried to get programmatically the name of the caller method by inspecting the StackTrace (for example, using System.Environment.StackTrace) but this is prone to errors since in Release mode the compiler could eliminate some methods by inlining them and you’ll be screwed. Plus the penalty would be higher than reflecting an expression.

The new mechanism in .NET 4.5 is type-safe, has no runtime performance penalty and it’s more elegant. Here’s how you can use it :

public abstract class ViewModelBase : INotifyPropertyChanged
{
    protected void NotifyPropertyChanged([CallerMemberName] string propertyName = null)
    {
        var deleg = PropertyChanged;
        if (deleg != null)
        {
            deleg(this, new PropertyChangedEventArgs(propertyName));
        }
    }

    public event PropertyChangedEventHandler PropertyChanged;
}

public class PersonViewModel : ViewModelBase
{
    private string _name;
    public string Name
    {
        get { return _name; }
        set
        {
            if (_name == value) return;
            _name = value;
            NotifyPropertyChanged();
        }
    }
}

I’ve recently built a very small GuidGen utility (which as the name implies generates GUIDs, copies it in the Windows Clipboard and stores a history of past generated GUIDs). You can browse some of the code and check out the project.

Much nicer, isn’t it?

Funny thing, this new mechanism can be used for non-UI tasks. For example if you have a project that uses and RDBMS and you use stored procedures. Let’s say you have one method in a repository class for each stored procedure, and even more, the method’s name matches the stored procedure’s name :

public VerificationResult VerifyUser(VerificationData verificationData)
{
    if (EmailValidator.IsEmailInvalid(verificationData.EmailAddress))
        throw new FormatException("emailAddress");

    var result = CreateNewCommand("VerifyUser").GetEnumResult<VerificationFailReason>(
        CreateEmailAddressParameter(verificationData.EmailAddress),
        CreateUniqueIdentifierParam("@VerificationCode", verificationData.VerificationCode));

    return new VerificationResult(result);
}

Observe on line 5 how the call to CreateNewCommand passes a string which matches the current method’s name. This can also be simplified (and become refactor-safe) using the new CallMemberName mechanism.

So you can’t really say that CallMemberName is useful only for UI tasks :)

License

This article, along with any associated source code and files, is licensed under The Code Project Open License (CPOL)

About the Author

Andrei Rinea
Software Developer (Senior) IBM, Business Analytics
Romania Romania
Member
No Biography provided

Sign Up to vote   Poor Excellent
Add a reason or comment to your vote: x
Votes of 3 or less require a comment

Comments and Discussions

 
You must Sign In to use this message board.
Search this forum  
    Spacing  Noise  Layout  Per page   
GeneralMy vote of 3memberwvd_vegt27 Aug '12 - 22:43 
Nice idea but using strings cripples it severely when refactoring (or typing in general).
 
ReflectionHelper like code (Linq based works file already) will enabled decent refactoring.
GeneralRe: My vote of 3 PinmemberAndrei Rinea27 Aug '12 - 23:34 
Well only the first solution is prone to this refactoring problems. If you read the whole article you'll see some reflection-based approaches which are refactor-safe and in the end the best solution, using the CallMemberName attribute.
 
Please read the whole article, especially starting from "The new mechanism in .NET 4.5 is type-safe, has no runtime performance penalty and it’s more elegant. Here’s how you can use it :"

GeneralRe: My vote of 3 Pinmemberwvd_vegt28 Aug '12 - 0:39 
Hi
 
You're right, I misread the last piece of code (and did not see any sample code of how the second piece of code could be inserted into the first string example to improve it).
 
The reflectionhelper code indeed caches and is (after fixing some bugs and trimming fat) faster then reflecting every time.
 
The idea stays nice and is good a alternative to automated wrappers like NotifyPropertyWeaver[^] that does not need additional coding in the properties.
wvd_vegt

General General    News News    Suggestion Suggestion    Question Question    Bug Bug    Answer Answer    Joke Joke    Rant Rant    Admin Admin   

Permalink | Advertise | Privacy | Mobile
Web03 | 2.6.130516.1 | Last Updated 27 Aug 2012
Article Copyright 2012 by Andrei Rinea
Everything else Copyright © CodeProject, 1999-2013
Terms of Use
Layout: fixed | fluid