views:

267

answers:

3

Using WPF has made me a fan of INotifyPropertyChanged. I like to use a helper that takes an expression and returns the name as a string (see example code below). In lots of applications I see by very proficient programmers, however, I see code that handles the strings raw (see 2nd example below). By proficient I mean MVP types who know how to use Expressions.

To me, the opportunity for having the compiler catch mistakes in addition to easy refactoring makes the Exression approach better. Is there an argument in favor of using raw strings that I am missing?

Cheers, Berryl

Expression helper example:

public static string GetPropertyName<T>(Expression<Func<T, object>> propertyExpression)
    {
        Check.RequireNotNull<object>(propertyExpression, "propertyExpression");
        switch (propertyExpression.Body.NodeType)
        {
            case ExpressionType.MemberAccess:
                return (propertyExpression.Body as MemberExpression).Member.Name;
            case ExpressionType.Convert:
                return ((propertyExpression.Body as UnaryExpression).Operand as MemberExpression).Member.Name;
        }
        var msg = string.Format("Expression NodeType: '{0}' does not refer to a property and is therefore not supported", 
            propertyExpression.Body.NodeType);
        Check.Require(false, msg);
        throw new InvalidOperationException(msg);
    }

Raw strings example code (in some ViewModelBase type class):

        /// <summary>
    /// Warns the developer if this object does not have
    /// a public property with the specified name. This 
    /// method does not exist in a Release build.
    /// </summary>
    [Conditional("DEBUG"), DebuggerStepThrough]

    public void VerifyPropertyName(string propertyName) {
        // Verify that the property name matches a real,  
        // public, instance property on this object.
        if (TypeDescriptor.GetProperties(this)[propertyName] == null) {
            string msg = "Invalid property name: " + propertyName;

            if (ThrowOnInvalidPropertyName) throw new Exception(msg);
            else Debug.Fail(msg);
        }
    }

    /// <summary>
    /// Returns whether an exception is thrown, or if a Debug.Fail() is used
    /// when an invalid property name is passed to the VerifyPropertyName method.
    /// The default value is false, but subclasses used by unit tests might 
    /// override this property's getter to return true.
    /// </summary>
    protected virtual bool ThrowOnInvalidPropertyName { get; private set; }
+3  A: 

To me, the opportunity for having the compiler catch mistakes in addition to easy refactoring makes the Exression approach better. Is there an argument in favor of using raw strings that I am missing?

I agree, and personally, use the expression approach in my own code, in most cases.

However, there are two reasons I know of to avoid this:

  1. It is less obvious, especially to less experienced .NET developers. Writing RaisePropertyChanged(() => this.MyProperty ); is not always as obvious to people as RaisePropertyChanged("MyProperty");, and doesn't match framework samples, etc.

  2. There is some performance overhead to using expressions. Personally, I don't feel this is really that meaningful of a reason, since this is usually used in data binding scenarios (which are already slow due to reflection usage), but it is potentially a valid concern.

Reed Copsey
+2  A: 

The benefit of using the TypeDescriptor approach is that it enables dynamic property scenarios based on ICustomTypeDescriptor implementations where the implementation can effectively create dynamic property metadata on the fly for a type that is being described. Consider a DataSet whose "properties" are determined by the result set it is populated with for example.

This is something that expressions does not provide however because it's based on actual type information (a good thing) as opposed to strings.

Drew Marsh
Is the TypeDescriptor approach the same as what I'm calling raw strings, or a third alternative?
Berryl
oh, ok. I see it in the code sample I provided myself :-)
Berryl
Yeah, so basically instead of doing reflection themselves which would fall as flat on it's face as expressions, they actually use the TypeDescriptor architecture which is much more power and provides that extensibility I talked about. Naturally this comes with some overhead as well.
Drew Marsh
It turns out that expressions compliment methods that take raw strings and should be used whereever they can be. As Drew points out, the raw strings may have callers that don't lend themselves to this, and so are also useful.
Berryl
A: 

I wound up spending more time on this than I expected, but did find a solution that has a nice mix of safety/refactorability and performance. Good background reading and an alternate solution using reflection is here. I like Sacha Barber's solution even better (background here.

The idea is to use an expression helper for a property that will participate in change notification, but only take the hit once for it, by storing the resulting PropertyChangedEventArgs in your view model. For example:

private static PropertyChangedEventArgs mobilePhoneNumberChangeArgs =
        ObservableHelper.CreateArgs<CustomerModel>(x => x.MobilePhoneNumber);

HTH,
Berryl

Berryl