Performance Tip: Prefer (((Object) x)== null) to Object.ReferenceEquals(x,null)

What’s the best way in C# to test for a null reference? It turns out that there are a few different ways of doing this correctly, and that they have different speed and code size characteristics.

Consider overloading the == operator for some class Thing. A natural first attempt is as follows.

public static bool operator == (Thing u,Thing v)
{
  return  (u == null)
        ? (v == null)
        : u.Equals(v);
}

This won’t work – it will enter an infinite recursion loop.

This raises the question: is it even possible to perform a non-overloaded equality test for null? One idea is to try using the Object.ReferenceEquals method. This method returns true if u or v refer to the same instance or are both null, and returns false otherwise. Using Object.ReferenceEquals does in fact lead to a correct implementation:

public static bool operator == (Thing u,Thing v)
{
  return   Object.ReferenceEquals(u,null)
         ? Object.ReferenceEquals(v,null)
         : u.Equals(v);

Now let’s look at efficiency – this article’s main point. The above version of operator == that uses Object.ReferenceEquals generates 25 bytes of IL code. (All such statistics in this article are for .NET 2.0.) It also contains a method call for each of the two comparisons against null. It would be nice if the language translation sequence eliminated these calls. As of .NET version 2.0, the pre-JIT compiler doesn’t optimize away these calls. Maybe there is a logical reason why it can’t, or maybe the optimizer just happens not to do this optimization. It’s also conceivable that some version of the JIT compiler can recognize that one of its arguments is the constant null, and convert each call to Object.ReferenceEquals into a small number of assembly language instructions to test for null, without doing a method call.

In any case, there is another correct way that does not rely on any such optimizations happening:

public static bool operator == (Thing u,Thing v)
{
  return   (((Object) u) == null)
         ? (((Object) v) == null)
         : u.Equals(v);
}

The above code is less logically transparent than the version that uses Object.ReferenceEquals. But, this version translates to only 18 bytes of IL. Even if using Object.ReferenceEquals were to result in the same code outputted by the JIT compiler, there are methods where saving 7 bytes of IL code is the difference between having the method inlined and not. (The .NET 2.0 JIT compiler will not inline methods that are larger than 32 bytes.) Furthermore, we can rely on this version to not incur the overhead of method calls to Object.ReferenceEquals. So, when looking for best performance, it is probably better to use (((Object) u) == null) than Object.ReferenceEquals(u,null).

Incidentally, the .NET 2.0 documentation that is installed on my machine does not describe the behavior of the Object type’s == operator. This makes it a little harder than it might otherwise be to verify that one can use this operator to test for reference equality.

A well-behaved compiler will inline small methods such as the above Thing type’s == operator. In theory, after inlining, the compiler could determine that the operand can never be null, and eliminate the test altogether. Best of all, in my opinion, would be if null were not even in the programming language.