Overriding == operator. How to compare to null?

C#.NetNullOverloadingOperator Keyword

C# Problem Overview


> Possible Duplicate:
> How do I check for nulls in an ‘==’ operator overload without infinite recursion?

There is probably an easy answer to this...but it seems to be eluding me. Here is a simplified example:

public class Person
{
   public string SocialSecurityNumber;
   public string FirstName;
   public string LastName;
}

Let's say that for this particular application, it is valid to say that if the social security numbers match, and both names match, then we are referring to the same "person".

public override bool Equals(object Obj)
{
    Person other = (Person)Obj;
    return (this.SocialSecurityNumber == other.SocialSecurityNumber &&
        this.FirstName == other.FirstName &&
        this.LastName == other.LastName);
}

To keep things consistent, we override the == and != operators, too, for the developers on the team who don't use the .Equals method.

public static bool operator !=(Person person1, Person person2)
{
    return ! person1.Equals(person2);
}

public static bool operator ==(Person person1, Person person2)
{
    return person1.Equals(person2);
}

Fine and dandy, right?

However, what happens when a Person object is null?

You can't write:

if (person == null)
{
    //fail!
}

Since this will cause the == operator override to run, and the code will fail on the:

person.Equals()

method call, since you can't call a method on a null instance.

On the other hand, you can't explicitly check for this condition inside the == override, since it would cause an infinite recursion (and a Stack Overflow [dot com])

public static bool operator ==(Person person1, Person person2)
{
    if (person1 == null)
    {
         //any code here never gets executed!  We first die a slow painful death.
    }
    return person1.Equals(person2);
}

So, how do you override the == and != operators for value equality and still account for null objects?

I hope that the answer is not painfully simple. :-)

C# Solutions


Solution 1 - C#

Use object.ReferenceEquals(person1, null) or the new is operator instead of the == operator:

public static bool operator ==(Person person1, Person person2)
{
    if (person1 is null)
    {
         return person2 is null;
    }

    return person1.Equals(person2);
}

Solution 2 - C#

I've always done it this way (for the == and != operators) and I reuse this code for every object I create:

public static bool operator ==(Person lhs, Person rhs)
{
    // If left hand side is null...
    if (System.Object.ReferenceEquals(lhs, null))
    {
        // ...and right hand side is null...
        if (System.Object.ReferenceEquals(rhs, null))
        {
            //...both are null and are Equal.
            return true;
        }

        // ...right hand side is not null, therefore not Equal.
        return false;
    }

    // Return true if the fields match:
    return lhs.Equals(rhs);
}

"!=" then goes like this:

public static bool operator !=(Person lhs, Person rhs)
{
    return !(lhs == rhs);
}

Edit
I modified the == operator function to match Microsoft's suggested implementation here.

Solution 3 - C#

you could alway override and put

(Object)(person1)==null

I'd imagine this would work, not sure though.

Solution 4 - C#

Easier than any of those approaches would be to just use

public static bool operator ==(Person person1, Person person2)   
{   
    EqualityComparer<Person>.Default.Equals(person1, person2)
} 

This has the same null equality semantics as the approaches that everyone else is proposing, but it's the framework's problem to figure out the details :)

Solution 5 - C#

The final (hypothetical) routine is below. It is very similar to @cdhowie's first accepted response.

public static bool operator ==(Person person1, Person person2)
{
    if (Person.ReferenceEquals(person1, person2)) return true;
    if (Person.ReferenceEquals(person1, null)) return false; //*
    return person1.Equals(person2);
}

Thanks for the great responses!

//* - .Equals() performs the null check on person2

Solution 6 - C#

Cast the Person instance to object:

public static bool operator ==(Person person1, Person person2)
{
    if ((object)person1 == (object)person2) return true;
    if ((object)person1 == null) return false;
    if ((object)person2 == null) return false;
    return person1.Equals(person2);
}

Solution 7 - C#

Cast the Person to an Object and then perform the comparison:

object o1 = (object)person1;
object o2 = (object)person2;
if(o1==o2) //compare instances.
   return true;
if (o1 == null || o2 == null)  //compare to null.
   return false;
//continue with Person logic.

Solution 8 - C#

Overloading these operators consistently is pretty hard. My answer to a related question may serve as a template.

Basically, you first need to do a reference (object.ReferenceEquals) test to see if the object is null. Then you call Equals.

Solution 9 - C#

cdhowie is on the money with the use of ReferenceEquals, but it's worth noting that you can still get an exception if someone passes null directly to Equals. Also, if you are going to override Equals it's almost always worth implementing IEquatable<T> so I would instead have.

public class Person : IEquatable<Person>
{
  /* more stuff elided */

  public bool Equals(Person other)
  {
    return !ReferenceEquals(other, null) &&
      SocialSecurityNumber == other.SocialSecurityNumber &&
      FirstName == other.FirstName &&
      LastName == other.LastName;
  }
  public override bool Equals(object obj)
  {
    return Equals(obj as Person);
  }
  public static bool operator !=(Person person1, Person person2)
  {
    return !(person1 == person2);
  }
  public static bool operator ==(Person person1, Person person2)
  {
    return ReferenceEquals(person1, person2)
      || (!ReferenceEquals(person1, null) && person1.Equals(person2));
  }
}

And of course, you should never override Equals and not override GetHashCode()

public override int GetHashCode()
{
   //I'm going to assume that different
   //people with the same SocialSecurityNumber are extremely rare,
   //as optimise by hashing on that alone. If this isn't the case, change this
   return SocialSecurityNumber.GetHashCode();
}

It's also worth noting that identity entails equality (that is, for any valid concept of "equality" something is always equal to itself). Since equality tests can be expensive and occur in loops, and since comparing something with itself tends to be quite common in real code (esp. if objects are passed around in several places), it can be worth adding as a shortcut:

  public bool Equals(Person other)
  {
    return !ReferenceEquals(other, null) &&
      ReferenceEquals(this, other) ||
      (
        SocialSecurityNumber == other.SocialSecurityNumber &&
        FirstName == other.FirstName &&
        LastName == other.LastName
      );
  }

Just how much of a benefit short-cutting on ReferenceEquals(this, other) is can vary considerably depending on the nature of the class, but whether it is worth while doing or not is something one should always consider, so I include the technique here.

Attributions

All content for this solution is sourced from the original question on Stackoverflow.

The content on this page is licensed under the Attribution-ShareAlike 4.0 International (CC BY-SA 4.0) license.

Content TypeOriginal AuthorOriginal Content on Stackoverflow
QuestionFlipsterView Question on Stackoverflow
Solution 1 - C#cdhowieView Answer on Stackoverflow
Solution 2 - C#Mike WebbView Answer on Stackoverflow
Solution 3 - C#rtpgView Answer on Stackoverflow
Solution 4 - C#startView Answer on Stackoverflow
Solution 5 - C#FlipsterView Answer on Stackoverflow
Solution 6 - C#dtbView Answer on Stackoverflow
Solution 7 - C#Greg SansomView Answer on Stackoverflow
Solution 8 - C#Konrad RudolphView Answer on Stackoverflow
Solution 9 - C#Jon HannaView Answer on Stackoverflow