DEV Community

Zohar Peled
Zohar Peled

Posted on • Updated on • Originally published at zoharpeled.wordpress.com

The perfect non-null test

Update: c# 9 has an even better option.

tl;dr; - if(x is object) {/* x is not null */}

Prior to c#8, all reference types where nullable in c#.

This means that we had to have some reliable way of making sure a reference is not null before using this reference, otherwise, we risk a NullRefereceException being thrown at run time.

Over the years, newer c# versions provided better ways of checking this.

We started with the naive

if(x != null) 
{
    // Do something with x here
}
Enter fullscreen mode Exit fullscreen mode

This is naive because the != (and ==) operator can be overloaded in c#, meaning that using this operator between a constant (null) and any type might yield unexpected results, if that type happen to overload the != operator in a way that wouldn't produce the results you would normally expect.

c#6 introduced the null conditional operators: ?. and ?[] - which means that you can access an instance member (a method, indexer or property) of a type, if the instance is not null.

If the instance is null, the method will not be invoked, or the property or indexer will not be accessed - but the result of the entire expression would be null (which could be easily handled with the already existing null coalescing operator: ??).

c#7 introduced pattern matching. Now you can check for null like this:

if(x is null)
{
   // do stuff if it's null
}
else 
{ 
    // do stuff if it's not 
} 
Enter fullscreen mode Exit fullscreen mode

A lot of c# developers, including myself, was missing a much more useful check: is not null.
Personally, I used to simply do this:

if(!(x is null))
{
   // do stuff if x is not null
}
Enter fullscreen mode Exit fullscreen mode

Which makes a rather ugly code, but at least it's safe.
Then I saw this tweet by Jared Parsons:

Which got me thinking: Why is checking x is object the perfect non-null test in c#? So I've tried googling c# is object and all sort of stuff along these lines, only to come up blank.
When that failed, the obvious option would be to go read the documentation of the is operator more carefully - and sure enough - there it was:

When using the type pattern to perform pattern matching, is tests whether an expression can be converted to a specified type and, if it can be, casts it to a variable of that type.

expr is type varname

where expr is an expression that evaluates to an instance of some type, type is the name of the type to which the result of expr is to be converted, and varname is the object to which the result of expr is converted if the is test is true.

So far no indication of a null test, but then, in the next line:

The is expression is true if expr isn't null, and any of the following is true:

(going on listing the conditions).

Since any type in c# is compatible with object, this means that the expression
x is object can only evaluate to false if x is null - which makes it the perfect non-null test.

Another benefit is that just like the compiler will not let you use x is null when x is a value type, it will issue a warning (CS0183) when attempting to use x is object if x is a value type:

warning CS0183: The given expression is always of the provided (‘object’) type

Latest comments (10)

Collapse
 
monkey0506 profile image
Michael Rittenhouse

So, now I have this.

public static bool operator ==(Widget? lhs, Widget? rhs)
{
    return lhs is object ? lhs.Equals(rhs) : rhs is null;
}

I kind of like it. :)

Collapse
 
glenn_k_smith profile image
Glenn Smith

Visual Studio 2019 is giving me a odd compiler error when I use the following code:

// contrived code
public void Test(DateTime dt, string message)
{
if (dt != null) // compiles ok
{
// do something
}

if (!(dt == null)) // compiles ok
{
// do something
}

if (!(dt is null)) // error CS0037: Cannot convert null to 'DateTime' because it is a non-nullable value type
{
// do something
}
}

If DateTime is non-nullable, why do the first two if statements compile? Or, if any type in c# is compatible with object, why does the compiler complain?

Collapse
 
peledzohar profile image
Zohar Peled

the fact that a type is non-nullable doesn't prevent you from asking if it equals null. Remember that == (and !=) can be overloaded and this means that you could have a struct with == and != overloads that specially treat null.
The is operator, on the other hand, can't be overloaded - so the compiler can and will issue an error when attempting to check if a non-nullable type is null.

If you add if(dt is object) you should be getting true every time, since dt is non-nullable.

Collapse
 
seangwright profile image
Sean G. Wright

Been using this syntax for awhile. We don't have any != null or == null in our code base.

It's much more readable. 👍

Collapse
 
ahmaddeel profile image
AhmadDeel

Is object different from struct? What if we have struct and "is object" fails?

Collapse
 
peledzohar profile image
Zohar Peled

object is the ultimate base type for all .Net types. structs implicitly inherits the ValueType class which inherits object, and by definition are value types, meaning they can't be null to begin with - which means that this test will always return true.

Collapse
 
tcgumus profile image
Tuna Çağlar Gümüş

Thank you Zohar.

Collapse
 
thomaslevesque profile image
Thomas Levesque

You can use x is {} too in C# 8

Collapse
 
stevengamer193 profile image
Steven Gamer

if (eyes.opened) {
Jaw.dropped = true;
ShowAppreciation();
}

// Thank you! I will definitely
// use this in my code moving
// forward. One big thing about
// it is the fact it's READABLE!

Collapse
 
patricnox profile image
PatricNox • Edited

In PHP I tend to use the irreversible op on null coalesce op for such scenarios

(! $condition) ?? makeCoolProject();