Snippet: Strongly typed property names

Last night at the QMSDNUG someone asked whether it was possible to implement INotifyPropertyChanged without hard-coding property names as strings inside code. For example, you would normally write:

public string FirstName
{
    get { return _firstName; }
    set
    {
        _firstName = value;
        this.OnPropertyChanged(new PropertyChangedEventArgs("FirstName"));
    }
}

Unfortunately the default refactoring tools won’t search in string literals, so if LastName was renamed to Surname, you’d need to change the string manually.

One option to enforce compile-time detection would be the following:

public string FirstName
{
    get { return _firstName; }
    set
    {
        _firstName = value;
        this.OnPropertyChanged(Property.GetFor( () => this.Name ));
    }
}

It could be implemented quite simply with the following static method:

public class Property
{
    public static PropertyChangedEventArgs GetFor(Expression<Func<object>> propertyNameLambda)
    {
        MemberExpression member = propertyNameLambda.Body as MemberExpression;
        if (member != null)
        {
            return new PropertyChangedEventArgs(member.Member.Name);
        }
        return new PropertyChangedEventArgs("");
    }
}

Personally, I don’t mind hard-coding property names too much, but it’s hardly a best practices, so you may find the above useful. Just beware that it does come with some overhead at runtime. Challenge: can anyone think of a clever way to cache it?

24 Responses to “Snippet: Strongly typed property names”

  1. I think using reflection or expression parsing is probably overkill.

    After you mentioned the idea in your SyncLINQ talk at CodeCamp Oz, I’ve started taking a similar approach as WPF does with its dependency properties: Define a static PropertyChangedEventArgs at the top of each class, like this:

    private static PropertyChangedEventArgs FooProperty = new PropertyChangedEventArgs(”Foo”);

    Then I can simply pass FooProperty to my OnPropertyChanged method, and also use FooProperty.PropertyName in my IDataErrorInfo’s this[columnName] implementation.

  2. Hi Matt,

    I do that too, and it’s what I suggested originally, but it does have the disadvantage of still having a string (even in just one place). Personally though I don’t mind.

    Paul

  3. I don’t think you’ll be able to do caching to the point where you’re going to be able to have any noticable impact on any applications speed while preventing for a blown-out memory usage.

    It’s really a catch 22 situation, you’ll want to cache if you’re doing a lot of these event raises and that implied that you have a lot of properties. So you end up caching a large number of these which will increase the memory footprint of the application.

    Also, you’ll need to check the cache each time (unless you want to be really nasty and presume it to exist…) which will add clock cycles, and then ultimately a read from the memory.
    So the question then becomes which is faster, executing the code every time or reading from memory.

  4. How can this
    () => this.Name
    be replicated in VB.net?

  5. […] Strongly Typed Property Names (Paul Stovell) […]

  6. You have a typo,

    Property.GetFor( () => this.Name )

    Should read:

    Property.GetFor( () => this.FirstName )

    A very neat solution, haven’t seen anybody digging into expression trees to solve such problems before.

    David.

  7. The FooProperty doesn’t give you refactoring support, and the GetFor has runtime overhead. You asked how you’d cache this to remove the overhead. Well, that’s easy. Use both methods!

    private static PropertyChangedEventArgs FooProperty = new PropertyChangedEventArgs(Property.GetFor(() => new Person().FirstName);

    The temporary required in the GetFor here adds even more overhead (though only during initialization), so it would probably be beneficial to do this in a static constructor so you have one temporary for all properties.

    I don’t know if I prefer this approach, or simply including an assert in debug mode to check at runtime that the property actually exists. Something worth considering.

  8. Another way would be to walk up the stack and get the method name:

    private void OnPropertyChanged()
    {
    var pc = PropertyChanged;
    if (null != pc)
    {
    var st = new StackFrame(1);

    pc( this, new PropertyChangedEventArg( st.GetMethod().Name.Substring( 4 ) ) );
    }

    This would only get the stack frame if there was a subscriber to the event. Looking at the disassembly for the Expression tree version shows a lot of code executed in each property setter to generate the expression tree each time, this way you’d only need an OnPropertyChanged(); call in the property setter, it could also be refactored as an extension method so all a class would need is the public event PropertyChanged declaration.

  9. David,

    Yeah, something interesting about that idea. We were actually doing that for a while. Then we started noticing some property change events weren’t being fired. Some diagnostic trace messaging revealed that in release builds, the stack trace often didn’t contain the property setter call. I’ve NO clue what would cause that. Seems a pretty serious problem even with out this trick. However, we had to abandon this method because it wasn’t reliable.

  10. wekempf,

    I wondered about that scenario after I posted, guess you would also need:

    [MethodImpl( MethodImplOptions.NoInlining )]

    On all the setter methods and the OnPropertyChanged() otherwise some of them will be optimised away.

    It seems that just using the property name as a string is the simplest solution, and the static PropertyChangedEventArgs when you’re most concerned about performance. I’ve never used it but perhaps something like FxCop could be configured to check in either case that the names all matched up in case you’d used the automatic refactoring and missed out a change.

    Still think the use of expression trees is neat though :-)

  11. David,

    I thought we checked that it wasn’t inlined, but maybe that was the culprit. Oh well, time pressure prevented us from evaluating the root cause, and we abandoned it.

    I’m not sure FxCop could do this. I know there’s no built-in rule to do it, at the very least. Thinking about what would be required, I’m just not sure you could roll one that would work. First, there’s too many patterns of usage to cover. More importantly, you won’t always report a property change only in the property’s setter. Imagine a property that’s dependent on another one. A Foo setter may fire a Bar property change notification, and there’s no way you’d figure that out through static analysis.

    What I wish we had was a language construct for symbols.

    OnPropertyChange(new PropertyChangeEventArg(`Foo.Bar)); // note the ` operator

    This would be statically checked and refactorable. Symbols are highly useful in all of the languages I’ve used that have them. They’d certainly be welcome in this case.

  12. If you are still using .NET 2.0 and VS2005, could you not accomplish it with this:

    public string FirstName
    {
    get { return _firstName; }
    set
    {
    _firstName = value;
    this.OnPropertyChanged(new PropertyChangedEventArgs(MethodBase.GetCurrentMethod().Name));
    }
    }

    You will have a “set_” prefixing the name but that can always be stripped off.

    Ken

  13. @eddy:

    OnPropertyChanged(Property.GetFor(Func() Me.Name))

    I *think* that would work.

  14. I found a project called PostSharp the other day that allows insertion of code based on attributes post build.

    I wonder if you could use that to make an attribute that automatically adds the OnPropertyChanged() call after compiling.

  15. Thanks for that, Paul! Very interesting approach.

  16. The problem with walking the stack is not just if the property gets in-lined, but if the routine(s) that call the property get in-lined. Also, GetCurrentMethod works, but when I tested I found that it had a greater performance impact than what I was comfortable with.

    So, I developed this solution: http://www.codeplex.com/ActiveSharp . I believe it’s currently the best solution available (for some definition of “best” ;-) It inspects your MSIL to figure out which field is used by each property. From that, it figures out the rest. You don’t need to put anything at all into the setter method to identify the property. It is refactoring-safe, and performs efficiently.

    Paul, your example would become this:

    public string FirstName
    {
    get { return _firstName; }
    set
    {
    SetValue( ref _firstName, value)
    }
    }

    Compact, readable and refactorable ;-)

  17. Hi,
    I tried something different for the PropertyChanged mechanics - I tried to add the behaviour through a proxy generated with “DynamicProxy2″, doing the event raising and all that. However, the attempts I tried conflicted with the reflection mechanisms in WPF. I think the idea isn’t that bad, and there may be a way to navigate around the issues. Need time to check.
    Here’s the write-up on it: http://realfiction.net/?q=node/156

  18. […] Paul Stovell talks about Strongly Typed Property Names. […]

  19. Regarding the PostSharp comment: yes, I have created one such solution and there is even an official example that does it.

    it is actually without a doubt the best solution because it alters the IL and as such has no overhead (like other aop solutions or the here proposed solution).

  20. Right, the only downside with postSharp is that you can’t edit-and-continue since it creates an optimized build.. well, that and the increased build time.

    Postsharp is great though, definitely worth checking out as you can accomplish some really neat things with it.

  21. It seems this is not quite enough for VB:
    OnPropertyChanged(Property.GetFor(Function() Me.Name))

    The VB compiler puts out a different expression tree than C#. The expression parameter Body is actually an instance of UnaryExpression, not MemberExpression as your C# code expects.

    A quick test in the GetFor method to test for UnaryExpression then grab the MemberExpression from aUnaryExp.Operand instead makes it more language agnostic.

    Yay for VB! :(

  22. Heres how its done in CSLA VB.

    Protected Sub PropertyHasChanged()

    Dim propertyName As String = _
    New System.Diagnostics.StackTrace(). _
    GetFrame(1).GetMethod.Name.Substring(4)
    PropertyHasChanged(propertyName)

    End Sub

  23. If you use ReSharper (and every .NET developer should!), then rename refactoring will search string literals as well as comments. While it’s not a perfect solution, the matching is reasonably intelligent.

    The ReSharper 4.0 Beta has full support for C# 3.0, LINQ, and even includes XAML support in its refactorings. You can grab a 30-day trial from jetbrains.com. I highly recommend it.

  24. The static approach is a bug waiting to happen.

    The whole show of data binding in WPF and WinForms is a mess.

    Something kind of obvious reading these comments.

Leave a Reply