重载 == 运算符抛出带有非空操作数的 NullReferenceException

overloaded == operator throwing NullReferenceException with non-null operands

我正在尝试实现 IEquatable<T> 接口和 == 运算符。尽管两个操作数都是非空的,但当我尝试使用 == 运算符时,下面的实现会触发 NullReferenceException 。我在最小示例代码中添加了注释,以准确显示异常发生的位置。我做错了什么?

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
        }
    }
}

编辑(澄清问题以回应重复的问题标记): 我不是在问 NullReferenceException 是什么(我理解)而且我对 ReferenceEquals 不感兴趣,因为我需要等同于对象的值。

Equals(TestClass) 中的行 other == null 调用相等运算符,它调用 Equals(TestClass) -- 无限循环。在第二轮中,other 为 null,当您将其作为 left 参数传递给相等运算符时会导致 NullReferenceException

您应该使用 ReferenceEquals(other, null)other is null

实际上,您的超载 equality operator 被击中 次:

First,当从 Program.Main(string[]) 调用行 tc1 == tc2 时,其中 left=tc1right=tc2,然后调用 TestClass.Equals(TestClass) 其中 other=tc2.

从那里,other == null 现在调用您的 重载相等运算符 时间,其中 left= tc2right=null。 现在,TestClass.Equals(TestClass) 也被称为 时间,其中 other=null.

最后,other == null 调用您的 重载相等运算符 第三次 次,其中两个 left =nullright=null。现在这最终会导致 System.NullReferenceException 因为 left 为空。

要修复此编码错误,请将 TestClass.Equals(TestClass) 中的 other == null 替换为 other is null:

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

或者,作为条件表达式(使用表达式主体):

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