Friday 4 February 2011

PostSharp AOP And PropertyChanged

Having previously written about implementing PropertyChanged and Unity Interception: http://jaseatwork.blogspot.com/2011/01/unity-interception-and-propertychanged.html
I was left feeling like the solution was a bit of a kludge. I also realised that out there in the ether there is a whole raft of developers trying to do the same thing.  When you start out looking at AOP in .NET you inevitably end up at PostSharp:
http://www.sharpcrafters.com/postsharp,
which is an excellent AOP framework that I've seen used on a project I've been involved in recently.  PostSharp was founded by Gael Fraituer in 2004 and it is now the leading .NET AOP framework.
There are some interesting postings by Gael on the differences between Dependency Injection and AOP:
http://www.sharpcrafters.com/blog/post/Aspect-Oriented-Programming-vs-Dependency-Injection.aspx
and an interesting and thought-provoking rebuke aimed at Anders Hejelsburg's disdain for inclusion of AOP into the next version of C#:

There on the site was an out-of-the box implementation of exactly what I was looking for: http://www.sharpcrafters.com/solutions/ui#data-binding
The ability to attribute NotifyPropertyChanged.  Gael provides further explanation of this here:
http://www.sharpcrafters.com/blog/post/introducing-postsharp-2-0-1-notifypropertychanged.aspx.

The only catch is that you need to buy the licensed professional version because the example introduces some advanced features.  So, I decided to see if I could write a version using only the unlicensed features. I found a few examples of people doing the same thing, but they all looked quite similar to Unity Interception, featuring some nasty reflection code: 
http://ruskin-dantra.blogspot.com/2009/03/inotifypropertychanged-made-easier.html
http://www.codeproject.com/KB/cs/NotifyingAttribute.aspx?msg=3001451


I was convinced that it must be easier than these examples so I signed up to the PostSharp forum, and was suprised to get someful helpful hints and suggestion from Gael himself... What a nice fella, he's helping me get something working which means I don't have to shell out for the professional licence!


The full blog is included here:
...And the code is here. I think you'll agree it's a lot nicer than the Unity Interception example, with all its caveats and "complexity".

using System;
using System.ComponentModel;
using PostSharp.Aspects;
using PostSharp.Extensibility;

namespace NotifyPropertyChanged
{    
    [Serializable]
    [MulticastAttributeUsage(MulticastTargets.Property,
    AllowMultiple = false, Inheritance = MulticastInheritance.Multicast)] 
    public sealed class NotifyPropertyChangedAttribute :
    LocationInterceptionAspect
    {
        public override void OnSetValue(LocationInterceptionArgs args)
        {
            if (args.Value == args.GetCurrentValue())
            {
                return;
            }

            ((BaseClass)args.Instance).
            OnPropertyChanged(args.Location.Name);
        
            args.ProceedSetValue();
        }
    }

    [NotifyPropertyChanged]
    public abstract class BaseClass : INotifyPropertyChanged
    {
        public void OnPropertyChanged(string propertyName)
        {
            if (this.PropertyChanged != null)
            {
                this.PropertyChanged(this,
                new PropertyChangedEventArgs(propertyName));
            }
        }

        public event PropertyChangedEventHandler PropertyChanged;
    }
        
    public class SomeEntityClass : BaseClass
    {
        public SomeEntityClass()
        {
        }
        
        public string SomeProperty
        {
            get;
            set;
        }        
    }
    
    class Program
    {
        static void Main(string[] args)
        {
            SomeEntityClass sec = new SomeEntityClass();
            sec.PropertyChanged += (sender, eventArgs) =>
            {
            };                   

            sec.SomeProperty = "Hello";           
        }
    }
}
No relection, no inheritance from MarshalByRefObject, no need to use the Unity factory to create objects, no need to make the property virtual and no need to wrap the event in a method...


STOP PRESS! Gael has just let me know that I have inadvertently used a Pro feature: Use of Inheritance = MulticastInheritance.Multicast in the MulticastAttributeUsage attribute.  This enabled me to put the [NotifyPropertyChanged] attribute on the base class and see the event fire.  Without this attribute I have to put the attribute on the derived class, otherwise my event doesn't get raised.  This is not quite as elegant, but I can live with it...

1 comment:

  1. This is a great comparison regarding the lines of code between Unity and PostSharp! :-)

    ReplyDelete