8

When I write this:

ReferenceEquals(x, null)

Visual studio suggests that the

null check can be simplified.

and simplifies it to

x is null

Are those really the same?

Michael Haddad
  • 4,085
  • 7
  • 42
  • 82
  • 1
    They are equivalent, yes. Although the former is more widely understood. The former is harder to get your head around - https://stackoverflow.com/questions/46666034/ – mjwills Feb 23 '18 at 10:12
  • Although under the hood, `ReferenceEquals` just calls `return a == b` - [see the source code](https://referencesource.microsoft.com/#mscorlib/system/object.cs,82), so the super-common `x == null` is just as valid – Rhumborl Feb 23 '18 at 10:14
  • 4
    @Rhumborl: no -- only if `x` is of a type that does not overload `operator==`. `ReferenceEquals` will never hit that overload (since it operates on values statically typed as `object`), but if you write `==` in your code yourself, you very well can. – Jeroen Mostert Feb 23 '18 at 10:16
  • 2
    @Rhumborl It's true that `ReferenceEquals` just calls `a == b`. Howerver, since is takes `object` arguments, `ReferenceEquals(x,null)` isn't equivalent to `x == null`, but to `((object)x) == ((object)null)`. – relatively_random Oct 29 '18 at 13:24

4 Answers4

11

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)
}
mdebeus
  • 1,928
  • 3
  • 18
  • 27
3

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.

Richard
  • 106,783
  • 21
  • 203
  • 265
2

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.

Ansi9200
  • 31
  • 6
1

They mean the same in this case, yes. Most would use x == null though.

I guess ReferenceEquals could be little bit confusing because actually null is a literal that means no reference at all. How can any reference be equal to no reference?

Note that x is null is only allowed with C#7 and it's pattern matching feature. Normally you use is to check if x is a compatible type but null is not a type. So this is a bit confusing as well.

That's why i prefer x == null

Tim Schmelter
  • 450,073
  • 74
  • 686
  • 939
  • That is actually what confused me. – Michael Haddad Feb 23 '18 at 10:18
  • 1
    Also, why `x is null` is viable? According to MSDN: "[is] Checks if an object is compatible with a given type". Is `null` a type? – Michael Haddad Feb 23 '18 at 10:21
  • 1
    @Sipo: You're right, that's the reason why i prefer `== null` over `is null` ;-) – Tim Schmelter Feb 23 '18 at 10:26
  • 7
    I downgraded this answer because it could lead to a stack overflow for those objects that implement operator==(x), and then call x == null in that method. That is why there is a ReferencEquals method or why you need to use x is null – mdebeus Aug 10 '18 at 23:38