Mitigating The Billion Dollar Mistake - Fody Edition

local_offer
bottom view of concrete spiral stair

Photo by Len Cruz

Phil Haack recently wrote a post in which he talked about protecting C# code from null references by automatically adding guard code. Phil's implementation used PostSharp for the post compile injection. Instead I wanted to use Fody.

Fody vs PostSharp

Fody and PostSharp are both post-compile tools that add extra code into your assembly. This is known as Aspect Orientated Programming and can be very useful for certain tasks.

PostSharp takes the approach of injecting generic hook code into your assembly, and then calling out to your aspect at runtime. Your aspect then runs, doing any code analysis and reflection at runtime to do it's work. (This was my experience with PostSharp V1 ages ago. Apparently you can do some reflection at compile time in V2.1, but not all of it. See the documentation.) The final assembly still needs a reference to PostSharp, as well as any aspects you have added.

Also, for a simple 1 line method PostSharp produces this.

// Note the [AllowNull] attribute is still in the code.
public void SomeMethod(string nonNullArg, [AllowNull] string nullArg)
{
    MethodExecutionArgs methodExecutionArgs = 
        new MethodExecutionArgs(this, new Arguments<string, string>
        {
            Arg0 = nonNullArg,
            Arg1 = nullArg
        });
    MethodExecutionArgs arg_25_0 = methodExecutionArgs;
    MethodBase m = SampleClass.<>z__Aspects.m15;
    arg_25_0.Method = m;
    SampleClass.<>z__Aspects.a3.OnEntry(methodExecutionArgs);
    if (methodExecutionArgs.FlowBehavior != FlowBehavior.Return)
    {
        Console.WriteLine(nonNullArg); // NOTE: This is our original line.
        SampleClass.<>z__Aspects.a3.OnSuccess(methodExecutionArgs);
    }
}

Not very clear at all!

In contrast, Fody extension only run at compile time. Fody uses Mono.Cecil to allow you to modify the IL before the Fody compile step writes the assembly back out. That assembly has no references to Fody, and the aspects are woven directly into the code. The problem with this approach is that you have to know IL in order to write your own Fody extension, whereas in PostSharp you just write a .NET assembly with the code you want executed at runtime.

// Attribute removed from compiled code.
public void SomeMethod(string nonNullArg, string nullArg) 
{
    if (nonNullArg == null)
    {
        throw new ArgumentNullException("nonNullArg");
    }
    Console.WriteLine(nonNullArg); // NOTE: This is our original line.
}

Much cleaner, and easier to understand what this code is doing.

How to use NullGuard

NullGuard is available via NuGet.

PM> Install-Package NullGuard.Fody

As an extension to Fody it will automatically include Fody as a dependency.

Other Extensions

There are a bunch of other extensions for Fody, so most of the time you won't need to write a custom extension. You can find them by searching for 'Fody' on NuGet.

Here are a few of my favourites.