Search code examples
c#iequatable

overloaded == operator throwing NullReferenceException with non-null operands


I'm trying to implement the IEquatable<T> interface and == operator. The implementation below triggers a NullReferenceException when I try to use the == operator despite the fact that both operands are non-null. I've added comments to the minimum example code to show exactly where the exception occurs. What am I doing wrong?

using System;

namespace scratchpad
{
    class TestClass : IEquatable<TestClass>
    {
        public int data;
        public TestClass(int d)
        {
            this.data = d;
        }
        public bool Equals(TestClass other)
        {
            if (other == null)
                return false;
            else
                return this.data == other.data;
        }

        public override bool Equals(object other)
        {
            if (other is TestClass)
                return this.Equals((TestClass)other);
            else //Includes null
                return false;
        }

        public override int GetHashCode()
        {
            return this.data;
        }

        public static bool operator ==(TestClass left, TestClass right)
        {
            return left.Equals(right); //This line triggers the NullReferenceException
        }

        public static bool operator !=(TestClass left, TestClass right)
        {
            return !left.Equals(right);
        }
    }

    class Program
    {
        static void Main(string[] args)
        {
            TestClass tc1 = new TestClass(10);
            TestClass tc2 = new TestClass(10);
            Console.WriteLine("tc1="+tc1.data); //Prints "tc1.data=10" fine
            Console.WriteLine("tc1="+tc1.data); //Prints "tc2.data=10" fine
            bool isEqual = tc1 == tc2; //NullReferenceException occur here
            Console.WriteLine("isEqual="+isEqual); //Never gets to here
        }
    }
}

Edit (to clarify question in response to duplicates question flags): I am not asking what a NullReferenceException is (I understand that) and I am not interested in ReferenceEquals as I need to equate the object's values.


Solution

  • Actually, your overloaded equality operator is hit three times:

    First, when called from Program.Main(string[]) with the line tc1 == tc2, where left=tc1 and right=tc2, which then calls TestClass.Equals(TestClass) where other=tc2.

    From there, other == null now calls your overloaded equality operator a second time, where left=tc2 and right=null. Now, TestClass.Equals(TestClass) is called also a second time, where other=null.

    And finally, other == null calls your overloaded equality operator for a third time, where both left=null and right=null. This now eventually causes the System.NullReferenceException because left was null.

    To fix this coding error, replace other == null with other is null in TestClass.Equals(TestClass):

    public bool Equals(TestClass other)
    {
        if (other is null)
            return false;
        else
            return data == other.data;
    }
    

    Alternatively, as conditional expression (using expression body):

    public bool Equals(TestClass other) => !(other is null) && data == other.data;