AOP — Enforce initialization with PostSharp

Oh, the Pain!

Now and again we all come across an object which requires ini­tial­iza­tion before it can be used but with noth­ing there to stop us from try­ing to use it before it’s ini­tial­ized.

In most cas­es you will get a seem­ing­ly unre­lat­ed excep­tion (e.g. null ref­er­ence when the object tries to use some resource which it expects to be set dur­ing ini­tial­iza­tion), which aren’t very help­ful at all when you try to debug/identify the prob­lem.

If you’re lucky, the object you’re using might have been designed with this in mind and gives you a mean­ing­ful excep­tion when you try to call a method which requires the object to be ini­tial­ized first, in which case it should be a straight­for­ward to fix your code accord­ing­ly. For the guys design­ing the class though, this usu­al­ly means they have to lit­ter their code with val­i­da­tion log­ic and often means dupli­cat­ed val­i­da­tion code or unnec­es­sary inher­i­tance just to encap­su­late the val­i­da­tion log­ic.

For­tu­nate­ly, with the help of Post­Sharp, a sim­ple attribute can take care of this chore for you with ease!

Define high level interface

First off, you need a nice and sim­ple inter­face like this:

/// <summary>
/// Marks a component which needs to be initialized before it can be used
/// </summary>
public interface IInitializable<T>
{
    bool IsInitialized { get; }

    void Initialize(T initObject);
}

InitializationRequiredAttribute

The attribute will look some­thing like this (in Post­Sharp 2):

[Serializable]
[AttributeUsage(AttributeTargets.Method, Inherited = false)]
public sealed class InitializationRequiredAttribute : MethodInterceptionAspect
{
    public override bool CompileTimeValidate(MethodBase method)
    {
        // make sure that the attribute is used in a type that implements the 
        // IInitializable interface
        if (!method.DeclaringType.GetInterfaces()
                   .Any(i => i.IsGenericType &&
                             i.GetGenericTypeDefinition() == typeof(IInitializable<>)))
        {
            throw new Exception(string.Format(
                "The [{0}] attribute can only be used in types that implement the [{1}] interface",
                GetType(), typeof(IInitializable<>)));
        }
        return base.CompileTimeValidate(method);
    }

    /// <summary>
    /// Checks the IsInitialized property before allowing the call to proceed
    /// </summary>
    public override void OnInvoke(MethodInterceptionArgs eventArgs)
    {
        var propertyInfo = eventArgs.Instance.GetType().GetProperty("IsInitialized");
        if (propertyInfo != null)
        {
            var propertyValue = propertyInfo.GetValue(eventArgs.Instance, null);
            if (propertyValue != null && propertyValue is bool && (bool) propertyValue)
            {
                // only proceed with the call if the instance has been initialized
                eventArgs.Proceed();
                return;
            }
        }
        throw new InstanceNotInitializedException(eventArgs.Method.Name);
    }
}

I have enforced a rule that this attribute can only be used in a class which imple­ments our IIni­tial­iz­able inter­face, you can relax this rule by remov­ing the over­rid­den Com­pile­TimeVal­i­date method. How­ev­er, in my expe­ri­ence it’s best to not leave any grey area in your code just in case you run into a sit­u­a­tion where you had expect­ed the attribute to do its job only to find out lat­er that something’s gone wrong because you had accidentally/purposely removed the IIni­tial­iz­able inter­face from your class.

Usage

To use the attribute:

public class MyClass : IInitializable<string>
{
    public bool IsInitialized { get; private set; }
    public void Initialize(string initializationData)
    {
        …
        IsInitialized = true;
    }

    [InitializationRequired]
    public void DoSomething() { }
}