Understanding obj == null vs obj is null in C# and Their Performance Impact

When working with null checks in C#, developers often use one of the following approaches:
if (obj == null) { /* do something */ } if (obj is null) { /* do something */ }
Both methods check if an object reference is null
, but there are important differences between them, especially regarding operator overloading, reliability, and performance.
In this article, we will explore these differences and analyze their performance impact.
1. The Equality Operator (obj == null)
The statement:
if (obj == null)
uses the equality operator (==
) to compare obj
to null
.
How it Works
- For reference types,
==
checks ifobj
refers tonull
in memory. - For value types,
==
typically checks for equality rather thannull
(unless nullable types are involved). - Custom classes can override
operator ==
, which might lead to unexpected behavior.
Example of an Overloaded ==
Operator
Consider the following custom class:
class MyClass { public static bool operator ==(MyClass a, MyClass b) { return false; // Always returns false, even if null! } public static bool operator !=(MyClass a, MyClass b) { return true; } }
Now, let’s test it:
MyClass obj = null; if (obj == null) { Console.WriteLine("obj is null"); } else { Console.WriteLine("obj is NOT null"); }
Expected Output? You might think "obj is null"
will be printed, but due to the overloaded ==
operator, it will actually print:
obj is NOT null
This demonstrates why obj == null
may not always work as expected in custom classes.
2. The Pattern Matching Approach (obj is null)
Introduced in C# 7.0, the is
keyword provides a more reliable way to check for null
:
if (obj is null)
Why is is null
More Reliable?
- It cannot be overridden, making it safe from custom
==
overloads. - It uses pattern matching, which is optimized for null checks.
Let’s revisit the overloaded operator example:
if (obj is null) { Console.WriteLine("obj is null"); }
Regardless of the overloaded ==
operator, this will always print:
obj is null
Thus, obj is null
guarantees accurate null checks, even in custom types.
3. Performance Comparison
While obj is null
is safer, does it have a performance cost? Let’s analyze.
IL Code Comparison
C# code is compiled into Intermediate Language (IL). Let’s see how both checks translate:
For obj == null
if (obj == null) { /* do something */ }
The IL generated:
ldloc.0 // Load obj ldnull // Load null ceq // Compare equality
For obj is null
if (obj is null) { /* do something */ }
The IL generated:
ldloc.0 // Load obj ldnull // Load null ceq // Compare equality
Result: No Performance Difference
Both approaches generate the same IL code, meaning there is no performance penalty for using is null
.
However, since is null
is safer (immune to overloaded operators), it is generally the preferred approach.
4. Best Practices: When to Use Which?
Approach | Can Be Overridden? | Safe for All Cases? | Performance Concern? |
---|---|---|---|
obj == null | ✅ Yes | ⚠️ No (if == is overloaded) | ❌ No |
obj is null | ❌ No | ✅ Yes (Always safe) | ❌ No |
✅ Use obj is null
when:
- Working with custom classes that may overload
==
. - Ensuring absolute reliability in null checks.
✅ Use obj == null
when:
- Working with simple reference types that do not override
==
. - Codebases that predate C# 7.0 and lack
is null
.
5. Conclusion
Both obj == null
and obj is null
perform equally well, but obj is null
is safer due to its immunity to overloaded operators.
If you’re working with modern C# (7.0 and later), it is recommended to always use is null
for null checks to avoid unexpected behavior.