Is there a difference between x is null and ReferenceEquals(x, null)?
I noticed a lot of answers specifying that x == null
, x is null
, and ReferenceEquals(x, null)
are all equivalent - and for most cases this is true. However, there is a case where you CANNOT use x == null
as I have documented below:
Note that the code below assumes you have implemented the Equals method for your class:
Do NOT do this - the operator == method will be called recursively until a stack overflow occurs:
public static bool operator ==(MyClass x1, MyClass x2)
{
if (x1 == null)
return x2 == null;
return x1.Equals(x2)
}
Do this instead:
public static bool operator ==(MyClass x1, MyClass x2)
{
if (x1 is null)
return x2 is null;
return x1.Equals(x2)
}
Or
public static bool operator ==(MyClass x1, MyClass x2)
{
if (ReferenceEquals(x1, null))
return ReferenceEquals(x2, null);
return x1.Equals(x2)
}
Are those really the same?
Semantically yes (assuming x
is not a value type). You're doing a null check which is the same for all reference types.
Implementation: no. x == null
or x is null
will be directly implemented as IL instructions but Object.ReferenceEquals(x, null)
will be a method call.1
Also note if the type of x
has overridden operator ==
then x == null
may not be equivalent (changing the semantics of null checks in an operator overload is, at best, poor code because no one expects such a semantic change).
1 Of course the optimiser could recognise this and just output the IL, you'll need to look at the IL to confirm this.
I realize that I'm supre-late to the party and that answers have been given, but I feel the need to summarize a bit since this is a thing I search for every 8-12 months or so and I'd like to have an explanation I can understand (hopefully, if it gets posted)..
1. ReferenceEquals(a,b)
This is the tried and tested method to perform a safe reference equality comparison. It basically performs (object)a == (object)b
(or something to that effect) and has the advantages that its use is instantly recognizable and it can't be overridden.
2. a == b
This method is the one that feels "natural" to most people (since most comparison done throughout C# will be done with this operator).
Default behaviour on reference types should be correct. However, this can be overloaded, which can lead to unexpected results (imagining a failed implementation of the operator overload).
Like @mdebeus said, an additional risk (however marginal even for a competent monkey that read a primer on C#) is causing a StackOverflowException
. This can appear when overloading == and != and using the operators inside the method itself.
3. a is b
OK so this is shiny new sort of sugary thing that we get. Microsoft describes is in this case with:
The is operator checks if the runtime type of an expression result is compatible with a given type.
[...]
The E is T expression returns true if the result of E is non-null and can be converted to type T by a reference conversion, a boxing conversion, or an unboxing conversion; otherwise, it returns false. The is operator doesn't consider user-defined conversions.
(read a complete description here)
The short of it is that this will return true if a can be converted through b via boxing, unboxing or covariance. As you would expect, this works very well against null.
All in all, as a personal note, although is makes things shorter and prettier for null check in equality overloading, I think I'll would still use ReferenceEquals, simply because I'm a control-freak and there is at least a part of how is works that worries me when it comes to cases of covariance.