Recently I wanted to use PostSharp for some simplistic lazy loading, but ended up hitting a couple of problems along the way. It all started very well – I defined an OnFieldAccessAttribute, removed the field in GetOptions() and overrided OnGetValue() to lazily create the type. My creation code was something like the following:

public override void OnGetValue(FieldAccessEventArgs eventArgs)
{
  if (eventArgs.StoredFieldValue == null)
    eventArgs.StoredFieldValue = Activator.CreateInstance(eventArgs.DeclaringType, args);
  eventArgs.ExposedFieldValue = eventArgs.StoredFieldValue;
}

Big mistake. For an uninitialized field, the declaring type is null. This means that it’s impossible to apply a [LazyLoad] attribute, since the aspect is clueless about the type of object to lazily load. The solution – passing the type :( Here it is:

[Serializable]
class LazyLoad : OnFieldAccessAspect
{
  private readonly Type type;
  private readonly object[] args;
  public LazyLoad(Type type, params object[] arguments)
  {
    this.type = type;
    args = arguments;
  }
  public override OnFieldAccessAspectOptions GetOptions()
  {
    return OnFieldAccessAspectOptions.RemoveFieldStorage;
  }
  public override void OnGetValue(FieldAccessEventArgs eventArgs)
  {
    if (eventArgs.StoredFieldValue == null)
      eventArgs.StoredFieldValue = Activator.CreateInstance(type, args);
    eventArgs.ExposedFieldValue = eventArgs.StoredFieldValue;
  }
}

This takes care of both the type to create and the arguments, so it can be used as follows:

class B
{
  public B()
  {
  }
  [LazyLoad(typeof(A))]
  public A A;
}

You don’t want to know what happend if A is a value type – really, you don’t. But the above code works, and lazy-loads the A variable only when accessed. So far so good, right? Well, yes, except there is a problem: sometimes I want to lazy-load a member, passing this into the constructor. I could make this super-complicated by overloading aspect constructors, but I decided to create a new aspect instead:

[Serializable]
class LazyLoadWithThis : OnFieldAccessAspect
{
  private readonly Type type;
  public LazyLoadWithThis(Type type)
  {
    this.type = type;
  }
  public override OnFieldAccessAspectOptions GetOptions()
  {
    return OnFieldAccessAspectOptions.RemoveFieldStorage;
  }
  public override void OnGetValue(FieldAccessEventArgs eventArgs)
  {
    if (eventArgs.StoredFieldValue == null)
      eventArgs.StoredFieldValue = Activator.CreateInstance(type, new[] {eventArgs.Instance});
    eventArgs.ExposedFieldValue = eventArgs.StoredFieldValue;
  }
}

There. That covers my needs. However, since there’s a myriad of Activator.CreateInstance() overloads, there’s probably a lot more one can do with lazy-loading aspects. Shame about the (somewhat) ugly syntax though – but then again, this lets you lazy-load polymorphically, if that’s your cup of tea. And I strongly suspect that lazy-loading semantics are domain-specific in most cases (they certainly are in my projects), so the above is only an example.