Different ways to check if a value is null in C#

 
 
  • Gérald Barré

In .NET, there are multiple ways to check if a value is null, but they are not all equivalent. Let's look at the different ways to check if an object is null:

C#
object obj = ...;

obj == null;
object.Equals(obj, null);
object.ReferenceEquals(obj, null);

obj is null;          // Equivalent to ReferenceEquals(obj, null)
(object)obj == null;  // Equivalent to ReferenceEquals(obj, null)
obj is not object;    // Equivalent to !ReferenceEquals(obj, null)
obj is not {};        // Equivalent to !ReferenceEquals(obj, null)

obj.Equals(null);     // doesn't work as it would throw a NullReferenceException

There are three main ways to perform a null check:

  • Object.ReferenceEquals(obj, null)

    ReferenceEquals returns true when the object instances are the same instance. In this case, it returns true when obj is null.

  • object.Equals(obj, null)

    Equals behaves like ReferenceEquals when one argument is null. However, its logic is more complex and it is slightly slower, as the method call is not always inlined.

  • obj == null

    The == operator behaves like ReferenceEquals unless the class defines a custom equality operator. When a custom operator is defined, the compiler uses it instead of the default one, so the comparison logic may not perform an actual null check. You can force the compiler to use the == operator defined on object by explicitly casting the value to object.

    C#
    var obj = new Sample();
    obj == null;         // return true as it calls Sample.op_Equality which always return true
    (object)obj == null; // return false as it calls object.op_Equality (ReferenceEquals)
    obj is null;         // return false as it calls object.op_Equality (ReferenceEquals)
    
    class Sample
    {
        public static bool operator ==(Sample? a, Sample? b) => true;
        public static bool operator !=(Sample? a, Sample? b) => false;
    }

Note that is null does not work with structs, except for Nullable<T>:

C#
MyStruct a = default;
_ = a is null; // Compilation error
_= a == null;  // Valid only if MyStruct implements a compatible == operator

Span<char> span = default;
_ = span is null; // Compilation error
_ = span == null; // ok as Span has a compatible == operator

int? b = null;
_ = b is null; // Ok, rewritten as !b.HasValue

Although is not null, is object, and is {} all perform the same null check, they differ in how pattern variables can be captured:

C#
if (obj is not null x) // Not valid
if (obj is object x)   // Ok, x is of type object
if (obj is {} x)       // Ok, x is of the same type as obj

#Additional resources

Do you have a question or a suggestion about this post? Contact me!

Follow me:
Enjoy this blog?