PostSharp 1.0 - First Impressions

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
_methods = new List();
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; }


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);


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

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:

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:

public sealed class TryOutPostSharp
public void RecordAndPlayback()
MyRecorder recorder = new MyRecorder();
Console.WriteLine("Starting to record");
recorder.SayHiTo("Blog subscribers");
recorder.AddSomeNumbers(10, 20);
Console.WriteLine("Starting to replay");
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 [] - Copyright (c) Gael Fraiteur and
Community, 2005-2007.
TryPostSharp ->

========== 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.

Written on October 2, 2007