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 ifobjrefers tonullin 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.
