123

The following will cause infinite recursion on the == operator overload method

    Foo foo1 = null;
    Foo foo2 = new Foo();
    Assert.IsFalse(foo1 == foo2);

    public static bool operator ==(Foo foo1, Foo foo2) {
        if (foo1 == null) return foo2 == null;
        return foo1.Equals(foo2);
    }

How do I check for nulls?

Alexei Levenkov
  • 98,904
  • 14
  • 127
  • 179
Andrew Jones
  • 5,217
  • 6
  • 25
  • 19

13 Answers13

149

Use ReferenceEquals:

Foo foo1 = null;
Foo foo2 = new Foo();
Assert.IsFalse(foo1 == foo2);

public static bool operator ==(Foo foo1, Foo foo2) {
    if (object.ReferenceEquals(null, foo1))
        return object.ReferenceEquals(null, foo2);
    return foo1.Equals(foo2);
}
bluish
  • 26,356
  • 27
  • 122
  • 180
Abe Heidebrecht
  • 30,090
  • 7
  • 62
  • 66
  • 1
    This solution does not work for `Assert.IsFalse(foo2 == foo1);` – FIL Nov 07 '18 at 10:10
  • And what does `foo1.Equals(foo2)` means if, for example, I want `foo1 == foo2` only if `foo1.x == foo2.x && foo1.y == foo2.y`? Isn't this answering ignoring the case where `foo1 != null` but `foo2 == null`? – Daniel Aug 28 '19 at 06:05
  • 6
    Note: The same solution with simpler syntax: `if (foo1 is null) return foo2 is null;` – Rémi Gaudin Jun 05 '20 at 10:34
20

Cast to object in the overload method:

public static bool operator ==(Foo foo1, Foo foo2) {
    if ((object) foo1 == null) return (object) foo2 == null;
    return foo1.Equals(foo2);
}
Andrew Jones
  • 5,217
  • 6
  • 25
  • 19
  • 1
    Exactly. Both `(object)foo1 == null` or `foo1 == (object)null` will go to the built-in overload `==(object, object)` and not to the user-defined overload `==(Foo, Foo)`. It is just like overload resolution on methods. – Jeppe Stig Nielsen Jun 04 '14 at 11:47
  • 2
    To future visitors - the accepted answer is a function, that executes the == of object. This is basically the same as the accepted answer, with one downside: It needs a cast. The accpeted answer is thus superior. – Mafii Jul 08 '16 at 12:43
  • 1
    @Mafii The cast is *purely* a compile time operation. Since the compiler knows that the cast cannot fail, it need not check anything at runtime. The differences between the methods are completely aesthetic. – Servy Jun 05 '17 at 20:43
10

If you are using C# 7 or later you can use null constant pattern matching:

public static bool operator==(Foo foo1, Foo foo2)
{
    if (foo1 is null)
        return foo2 is null;
    return foo1.Equals(foo2);
}

This gives you slightly neater code than the one calling object.ReferenceEquals(foo1, null)

jacekbe
  • 499
  • 1
  • 5
  • 18
8

Use ReferenceEquals. From the MSDN forums:

public static bool operator ==(Foo foo1, Foo foo2) {
    if (ReferenceEquals(foo1, null)) return ReferenceEquals(foo2, null);
    if (ReferenceEquals(foo2, null)) return false;
    return foo1.field1 == foo2.field2;
}
Jon Adams
  • 24,464
  • 18
  • 82
  • 120
4

There is actually a simpler way of checking against null in this case:

if (foo is null)

That's it!

This feature was introduced in C# 7

grooveplex
  • 2,492
  • 4
  • 28
  • 30
Reto Messerli
  • 41
  • 2
  • 4
4

Try Object.ReferenceEquals(foo1, null)

Anyway, I wouldn't recommend overloading the ==operator; it should be used for comparing references, and use Equals for "semantic" comparisons.

Jason Plank
  • 2,336
  • 5
  • 31
  • 40
Santiago Palladino
  • 3,522
  • 2
  • 26
  • 36
4

If I have overridden bool Equals(object obj) and I want the operator == and Foo.Equals(object obj) to return the same value, I usually implement the != operator like this:

public static bool operator ==(Foo foo1, Foo foo2) {
  return object.Equals(foo1, foo2);
}
public static bool operator !=(Foo foo1, Foo foo2) {
  return !object.Equals(foo1, foo2);
}

The operator == will then after doing all the null checks for me end up calling foo1.Equals(foo2) that I have overridden to do the actual check if the two are equal.

Hallgrim
  • 15,143
  • 10
  • 46
  • 54
  • This feels very appropriate; looking at the implementation of [`Object.Equals(Object, Object)`](http://referencesource.microsoft.com/mscorlib/system/object.cs.html#f2a579c50b414717) side by side with [`Object.ReferenceEquals(Object, Object)`](http://referencesource.microsoft.com/mscorlib/system/object.cs.html#4d607d6d56a93c7e), it's pretty clear that `Object.Equals(Object, Object)` does everything as suggested in the other answers out of the box. Why not use it? – tne Jun 19 '15 at 13:20
  • 1
    @tne Because there's no point overloading the `==` operator if all you want is default behavior. You should only overload when you need to implement custom comparison logic, i.e., something more than a reference equality check. – Dan Bechard Nov 24 '15 at 19:08
  • @Dan I'm confident you misunderstood my remark; in a context where it is already established that overloading `==` is desirable (the question implies it) I'm simply supporting this answer by suggesting that `Object.Equals(Object, Object)` makes other tricks like using `ReferenceEquals` or explicit casts unnecessary (thus "why not use it?", "it" being `Equals(Object, Object)`). Even if unrelated your point is also correct, and I would go further: only overload `==` for objects we can classify as "value objects". – tne Nov 25 '15 at 13:33
  • @tne The main difference is that `Object.Equals(Object, Object)` in turn calls [Object.Equals(Object)](http://referencesource.microsoft.com/#mscorlib/system/object.cs,517682d5f6f4f8b4) which is a virtual method that Foo likely overrides. The fact that you've introduced a virtual call into your equality check might affect the compiler's ability to optimize (e.g. inline) these calls. This is probably negligible for most purposes, but in certain cases a small cost in an equality operator can mean a huge cost for loops or sorted data structures. – Dan Bechard Nov 25 '15 at 19:28
  • @tne For more information about the intricacies of optimizing virtual method calls, refer to http://stackoverflow.com/questions/530799/what-are-the-performance-implications-of-marking-methods-properties-as-virtual. – Dan Bechard Nov 25 '15 at 19:29
  • @Dan Difference as compared to what? The casts are implicit thanks to the method signature, it does check for reference equality as an opportunistic fast path, checks for null references (the initial question) and finally calls the only sane method to call; it would be confusing to have the `Equals` override be different than `==` for a value object, and you wouldn't have a `==` overload if it wasn't one. You could do all this yourself in all of your `==` overloads, and yes you could manually inline even the structural equality code by duplicating it too, (...) – tne Nov 25 '15 at 23:11
  • (...) but at some point you're going to have to trust the JIT to do its job, otherwise consider that C# isn't the appropriate language for the task at hand. I'm quite familiar with inline expansion; avoiding virtual dispatch at C#-level is futile, even non-virtual calls are translated to `callvirt` instructions in the IL. All you *can* do is ensure a call site always targets the same runtime type to maximize the chances the JIT will emit a static dispatch or even inline the call. Anything else smells like cargo-cult practices. – tne Nov 25 '15 at 23:12
  • @tne All good points. I agree that it's probably cargo-cult in most, if not all cases, but I still find it curious that the [MSDN article](https://msdn.microsoft.com/en-US/library/ms173147(v=vs.80).aspx) omits any mention of calling object.Equals and explicitly recommends implementing the cast and null checks in the body of the derived class. I have neither the time nor necessity to follow up on the optimization suspicions, but I do very much appreciate your insights! – Dan Bechard Dec 01 '15 at 15:15
  • @Dan This is interesting indeed, the official guidelines are usually quite complete. It seems `Equals(Obj,Obj)` was there since the beginning too, so this can't be immediately explained with forgetfulness. The example code is semantically *exactly* the same as `Equals(Obj,Obj)`, except it implements the comparison code manually without `Equals(Obj)`. My best guess is that they didn't want to conflate the two and wanted to focus on the `==` override (it's not mandatory to override `Equals(Obj)`, although weird not to in this case). – tne Dec 01 '15 at 19:15
1

My approach is to do

(object)item == null

upon which I'm relying on object's own equality operator which can't go wrong. Or a custom extension method (and an overload):

public static bool IsNull<T>(this T obj) where T : class
{
    return (object)obj == null;
}

public static bool IsNull<T>(this T? obj) where T : struct
{
    return !obj.HasValue;
}

or to handle more cases, may be:

public static bool IsNull<T>(this T obj) where T : class
{
    return (object)obj == null || obj == DBNull.Value;
}

The constraint prevents IsNull on value types. Now its as sweet as calling

object obj = new object();
Guid? guid = null; 
bool b = obj.IsNull(); // false
b = guid.IsNull(); // true
2.IsNull(); // error

which means I have one consistent/not-error-prone style of checking for nulls throughout. I also have found (object)item == null is very very very slightly faster than Object.ReferenceEquals(item, null), but only if it matters (I'm currently working on something where I've to micro-optimize everything!).

To see a complete guide on implementing equality checks, see What is "Best Practice" For Comparing Two Instances of a Reference Type?

Community
  • 1
  • 1
nawfal
  • 70,104
  • 56
  • 326
  • 368
  • Nitpick: Readers should watch their dependencies before jumping on features like comparing `DbNull`, IMO the cases where this *wouldn't* generate issues related to [SRP](https://en.wikipedia.org/wiki/Single_responsibility_principle) are quite rare. *Just pointing out the code smell though, it could very well be appropriate.* – tne Jun 19 '15 at 10:03
0

The static Equals(Object, Object) method indicates whether two objects, objA and objB, are equal. It also enables you to test objects whose value is null for equality. It compares objA and objB for equality as follows:

  • It determines whether the two objects represent the same object reference. If they do, the method returns true. This test is equivalent to calling the ReferenceEquals method. In addition, if both objA and objB are null, the method returns true.
  • It determines whether either objA or objB is null. If so, it returns false. If the two objects do not represent the same object reference and neither is null, it calls objA.Equals(objB) and returns the result. This means that if objA overrides the Object.Equals(Object) method, this override is called.

.

public static bool operator ==(Foo objA, Foo objB) {
    return Object.Equals(objA, objB);
}
Zach Olivare
  • 3,805
  • 3
  • 32
  • 45
0

replying more to overriding operator how to compare to null that redirects here as a duplicate.

In the cases where this is being done to support Value Objects, I find the new notation to handy, and like to ensure there is only one place where the comparison is made. Also leveraging Object.Equals(A, B) simplifies the null checks.

This will overload ==, !=, Equals, and GetHashCode

    public static bool operator !=(ValueObject self, ValueObject other) => !Equals(self, other);
    public static bool operator ==(ValueObject self, ValueObject other) => Equals(self, other);
    public override bool Equals(object other) => Equals(other as ValueObject );
    public bool Equals(ValueObject other) {
        return !(other is null) && 
               // Value comparisons
               _value == other._value;
    }
    public override int GetHashCode() => _value.GetHashCode();

For more complicated objects add additional comparisons in Equals and a richer GetHashCode.

CCondron
  • 1,926
  • 17
  • 27
0

For a modern and condensed syntax:

public static bool operator ==(Foo x, Foo y)
{
    return x is null ? y is null : x.Equals(y);
}

public static bool operator !=(Foo x, Foo y)
{
    return x is null ? !(y is null) : !x.Equals(y);
}
mr5
  • 3,438
  • 3
  • 40
  • 57
-3

A common error in overloads of operator == is to use (a == b), (a ==null), or (b == null) to check for reference equality. This instead results in a call to the overloaded operator ==, causing an infinite loop. Use ReferenceEquals or cast the type to Object, to avoid the loop.

check out this

// If both are null, or both are same instance, return true.
if (System.Object.ReferenceEquals(a, b))// using ReferenceEquals
{
    return true;
}

// If one is null, but not both, return false.
if (((object)a == null) || ((object)b == null))// using casting the type to Object
{
    return false;
}

reference Guidelines for Overloading Equals() and Operator ==

Basheer AL-MOMANI
  • 14,473
  • 9
  • 96
  • 92
  • 1
    There are already multiple answers with all of this information. We don't need a 7th copy of the same answer. – Servy Oct 18 '16 at 13:07
-5

You can try to use an object property and catch the resulting NullReferenceException. If the property you try is inherited or overridden from Object, then this works for any class.

public static bool operator ==(Foo foo1, Foo foo2)
{
    //  check if the left parameter is null
    bool LeftNull = false;
    try { Type temp = a_left.GetType(); }
    catch { LeftNull = true; }

    //  check if the right parameter is null
    bool RightNull = false;
    try { Type temp = a_right.GetType(); }
    catch { RightNull = true; }

    //  null checking results
    if (LeftNull && RightNull) return true;
    else if (LeftNull || RightNull) return false;
    else return foo1.field1 == foo2.field2;
}
The Digital Gabeg
  • 2,765
  • 3
  • 21
  • 16
  • If you have many null objects then exception handling may be a big overhead. – Kasprzol Sep 16 '08 at 20:34
  • 2
    Haha, I agree that this is not the best method. After posting this method, I immediately revised my current project to use ReferenceEquals instead. However, despite being suboptimal it does work, and thus is a valid answer to the question. – The Digital Gabeg Sep 19 '08 at 01:26