tags:

views:

187

answers:

3

I've recently started experimenting with PostSharp and I found a particularly helpful aspect to automate implementation of INotifyPropertyChanged. You can see the example here. The basic functionality is excellent (all properties will be notified), but there are cases where I might want to suppress notification.

For instance, I might know that a particular property is set once in the constructor and will never change again. As such, there is no need to emit the code for NotifyPropertyChanged. The overhead is minimal when classes are not frequently instantiated and I can prevent the problem by switching from an automatically generated property to a field-backed property and writing to the field. However, as I'm learning this new tool, it would be helpful to know if there is a way to tag a property with an attribute to suppress the code generation. I'd like to be able to do something like this:

[NotifyPropertyChanged]
public class MyClass
{
    public double SomeValue { get; set; }

    public double ModifiedValue { get; private set; }

    [SuppressNotify]
    public double OnlySetOnce { get; private set; }

    public MyClass()
    {
        OnlySetOnce = 1.0;
    }
}
+3  A: 

You can use a MethodPointcut instead of a MulticastPointcut, i.e. use Linq-over-Reflection and filter against PropertyInfo.IsDefined(your attribute).

  private IEnumerable<PropertyInfo> SelectProperties( Type type )
    {
        const BindingFlags bindingFlags = BindingFlags.Instance | 
            BindingFlags.DeclaredOnly
                                          | BindingFlags.Public;

        return from property
                   in type.GetProperties( bindingFlags )
               where property.CanWrite &&
                     !property.IsDefined(typeof(SuppressNotify))
               select property;
    }

    [OnLocationSetValueAdvice, MethodPointcut( "SelectProperties" )]
    public void OnSetValue( LocationInterceptionArgs args )
    {
        if ( args.Value != args.GetCurrentValue() )
        {
            args.ProceedSetValue();

           this.OnPropertyChangedMethod.Invoke(null);
        }
    }
Gael Fraiteur
Excellent, thank you. This is a very powerful tool and my project feels significantly cleaner without all the tedious INotifyPropertyChanged plumbing.
Dan Bryant
A: 

FYI, I had some problems with the example on the Sharpcrafters website and had to make the following change:

    /// <summary>
    /// Field bound at runtime to a delegate of the method <c>OnPropertyChanged</c>.
    /// </summary>
    [ImportMember("OnPropertyChanged", IsRequired = true, Order = ImportMemberOrder.AfterIntroductions)]
    public Action<string> OnPropertyChangedMethod;

I think it was introducing the OnPropertyChanged member, but importing before it had a chance to be created. This would cause the OnPropertySet to fail because this.OnPropertyChangedMethod was null.

Dan Bryant