One of my favorite bits of .NET trivia is whether or not it is possible to observe a null value for this? Most developers I ask either say no, or yes but it requires incorrect IL / unsafe code. Since I’m writing this post you can probably guess that the answer is actually yes, this can indeed be null.

To demonstrate this behavior let’s start with a simple command line application:

class Program
{
    void Test()
    {
        if (this == null)
            Console.WriteLine("this is null");
    }

    static void Main(string[] args)
    {
        Program p = null;
        p.Test();
    }
}

No tricks here. Compiling and running this program will result in a NullReferenceException on the p.Test call exactly as a developer would expect. But how is this exception being generated? Lets take a look at the IL for this particular call using ildasm.

IL_0003:  ldloc.0
IL_0004:  callvirt   instance void NullThis.Program::Test()

The Test method is being invoked via the callvirt instruction. This performs a virtual dispatch of the target method. Part of the contract for this instructions is to throw a NullReferenceException if the target object, in this case p, is null. Hence this is the source of the exception.

But is callvirt necessary here? This is a non-virtual method so surely the virtual dispatch is unnecessary overhead. Let’s fix that by changing the instruction to call.

IL_0003:  ldloc.0
IL_0004:  call   instance void NullThis.Program::Test()

The new IL is legal and PEVerify clean. But what happens if we pass this through ilasm and run the resulting program?

$>ilasm /out:NullThis.exe /quiet NullThis.il 
$>NullThis.exe
this is null

Viola, our program has observed a null value for this.

The reason for the behavior change is the call instruction simply does not check for null as does callvirt. It passes along the target object as this without any inspection. This is one of the reasons why languages like C# will emit a callvirt instruction even for non-virtual methods. It serves as a cheap way of doing a null check on the target object.

Now after reading this some developers might wonder if they should start adding null checks for this to their code? No, please don’t. The standard .Net compilers (C#, VB, F#, etc …) will not emit IL that can observe a null value for this. Observing this behavior requires either hand crafting IL, using C++/CLI tricks or tricks with PInvoke and unsafe code. Not a situation that the majority of .NET applications out there will encounter.


Share Post

Google+

comments powered by Disqus