When C# 7.0 was officially released in March 2017 it introduced several new features to make the life of developers easier, like tuples and deconstruction, local functions, expression body definitions and, the focus of this article, pattern matching.
One of the advantages of pattern matching is a more concise syntax for testing expressions and taking actions when there’s a match, increasing the readability and correctness of your code.
Checking for nulls is one of the most common usages. Before C# 7.0, if a developer wanted to check if a given value was null, usually the equality comparison would be used.
1 | public static class PersonExtensions |
With pattern matching, the extension method would be using the is
operator and the null
constant to check if the person variable is null.
1 | public static class PersonExtensions |
The change is so small that you are probably questioning if changing the way you code is really worthy for such a small readability improvement, to have the same results?
And you are right in thinking that way since that’s probably true for 99% of use cases (if not 99.999%) but what if you really want to be sure it works every time?
You see, reference types can overload the ==
operator and, if the developer decides to always return false when comparing to null, the first example would throw a NullReferenceException
.
Let’s test that by overloading the ==
operator to always return false, whatever the parameters received:
1 | public class Person |
If we now call the extension method FullName
with a null argument a NullReferenceException
will be thrown instead of the expected ArgumentNullException
. This happens because the compiler knows there’s an equality overload, calls it and gets false, so if won’t enter the if statement.
If you look at the generated IL Code, you’ll see the Person equality operator being called.
1 | // [36 5 - 36 6] |
Before C# 7.0 if you wanted to be sure the ==
operator overload was ignored, you had to use object.ReferenceEquals
to compare the object reference to null.
1 | public static class PersonExtensions |
But when using pattern matching the compiler always generates code that compares to null, ignoring any ==
operator overload. This means you have the same behavior as using the object.ReferenceEquals
method without writing so much code.
1 | public class Person |
This ensures the method FullName
always throws ArgumentNullException
when a null reference is received.
Looking at the generated IL Code, we can see the person
reference is being compared to null using the ceq
instruction (this is exactly the same code if object.ReferenceEquals
was being used — it would be inlined).
1 | // [36 5 - 36 6] |
Conclusion
In this article I explained why using pattern matching for null checks is preferred to using the equality operator.
Not only it’s a small readability improvement but it also ensures the object reference is always compared to null even if the class has overloaded the ==
operator (same behavior as using the object.ReferenceEquals
method but without writing so much code).
Even if the equality operator overload is properly implemented, we can also consider this a small performance increase because executing the ceq operation is faster that a call to the class equality operator.
As stated before, this may not affect 99% of your use cases, but for such small a small change in the way you code, why not?