Tuesday, October 02, 2007
 Ok so I must've been sleeping under a rock or something, so this is no doubt old news to many people - but PostSharp completely slipped by without me noticing it until now... Having played with it tonight, I'm definitely liking it :)

So far I've just used it for doing some AOP... unlike doing AOP using something like Dynamic Proxy / AspectSharp in Castle, PostSharp gives you a more... personal experience... letting you apply AOP to internal or sealed types, and allowing you to declaratively setup aspects with very little effort... as an example I created a simple little class for recording and playing back methods out of sync... so, first off I have a recorder interface:

public interface IRecorder

{

    bool IsPlayback { get; }

    void RecordMethod(MethodInfo method, object[] parameters);

}


Following that I implemented a base class for recording the methods, and allowing for playback:

public class BaseRecorder : IRecorder

{

    private readonly List<RecordedMethod> _methods = new List<RecordedMethod>();

    private bool _isPlayback;

 

    #region IRecorder Members

 

    public void RecordMethod(MethodInfo method, object[] parameters)

    {

        _methods.Add(new RecordedMethod(method, parameters));

    }

 

    public bool IsPlayback

    {

        get { return _isPlayback; }

    }

 

    #endregion

 

    public void Playback()

    {

        try

        {

            _isPlayback = true;

 

            foreach (RecordedMethod method in _methods)

                method.Replay(this);

        }

        finally

        {

            _isPlayback = false;

        }

    }

 

    #region Nested type: RecordedMethod

 

    public class RecordedMethod

    {

        private readonly MethodInfo _method;

        private readonly object[] _parameters;

 

        public RecordedMethod(MethodInfo method, object[] parameters)

        {

            _method = method;

            _parameters = parameters;

        }

 

        public void Replay(object instance)

        {

            _method.Invoke(instance, _parameters);

        }

    }

 

    #endregion

}


Pretty basic - then I wrote myself the aspect - it really could not be simpler:

[Serializable]

public class MethodRecordAttribute : OnMethodInvocationAspect

{

    public override void OnInvocation(MethodInvocationEventArgs eventArgs)

    {

        IRecorder recorder = (IRecorder) eventArgs.Delegate.Target;

        object[] arguments = eventArgs.GetArguments();

        if (recorder.IsPlayback) eventArgs.Delegate.DynamicInvoke(arguments);

        else recorder.RecordMethod(eventArgs.Delegate.Method, arguments);

    }

}


And finally a demo... so I create a recorder class of my very own and decorate it with the attribute created above:

[MethodRecord]

public class MyRecorder : BaseRecorder

{

    public void SayHiTo(string name)

    {

        Console.WriteLine("Hi  {0}", name);

    }

 

    public void AddSomeNumbers(int x, int y)

    {

        Console.WriteLine("{0} + {1} = {2}", x, y, x + y);

    }

}


And now a quick demo:

[TestFixture]

public sealed class TryOutPostSharp

{

    [Test]

    public void RecordAndPlayback()

    {

        MyRecorder recorder = new MyRecorder();

        Console.WriteLine("Starting to record");

        recorder.SayHiTo("Alex");

        recorder.SayHiTo("Renee");

        recorder.SayHiTo("Blog subscribers");

        recorder.AddSomeNumbers(10, 20);

        Console.WriteLine("Starting to replay");

        recorder.Playback();

        Console.WriteLine("All done");

    }

}


The output is:

Starting to record
Starting to replay
Hi  Alex
Hi  Renee
Hi  Blog subscribers
10 + 20 = 30
All done


Which I think is pretty darn sweet, I can definitely see this having a place in my toolbox in the near future - especially when attempting to uphold DRY in some of my code - anyone using it on production projects in NZ at the moment?

So how does PostSharp pull it off?  Well it post-processes the compiled assembly... it does so by hooking in to an existing extension point in msbuild, so that the post-processor is executed for any project where it references the PostSharp.Public assembly.

All this means that you get to see a couple of extra lines in the build output during compilation:

Compile complete -- 0 errors, 0 warnings
PostSharp 1.0 [1.0.7.261] - Copyright (c) Gael Fraiteur and Community, 2005-2007.
TryPostSharp -> C:\dev\experiments\TryPostSharp\TryPostSharp\bin\Debug\TryPostSharp.dll
========== Rebuild All: 1 succeeded, 0 failed, 0 skipped ==========

But how does it really work? Well if we take a look at the list of 7 approaches to AOP Ayende did ... then it fits into the last two (Compile-time & Run-time IL Weaving).

If you have been living under a rock like myself I'd definitely suggest talking 10 minutes out of your day to give it a quick try.

posted @ Tuesday, October 02, 2007 10:15:34 AM (New Zealand Daylight Time, UTC+13:00)    Comments [1] | Trackback |
Search
FeedCount

Tags...
Who am I?
Alex Henderson
Alex Henderson
Auckland, New Zealand
Managing Director at Dev|Defined Limited

"Self Confessed Coding Junky for 15 years"
View Alex Henderson's profile on LinkedIn
 
Mobile: +64-21-402-969
Email: bittercoder 'at' gmail 'dot' com
MSN: bittercoder_nz@hotmail
Skype: alex.devdefined
Navigation