我正在尝试实现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
并不感兴趣,因为我需要将对象的值等同起来。
答案 0 :(得分:4)
other == null
中的行Equals(TestClass)
调用了相等运算符,该运算符调用了Equals(TestClass)
–无限循环。在第二轮中,other
为空,当您将其作为NullReferenceException
参数传递给相等运算符时,将导致left
。
您应该改用ReferenceEquals(other, null)
或other is null
。
答案 1 :(得分:3)
实际上,您超载的equality operator被命中了 3 次:
第一,当从Program.Main(string[])
用行tc1 == tc2
调用时,其中left
= tc1
和right
= {{ 1}},然后调用tc2
,其中TestClass.Equals(TestClass)
= other
。
从那里,tc2
现在将您的重载相等运算符调用 second 时间,其中other == null
= left
和{{ 1}} = tc2
。
现在,right
也称为秒时间,其中null
= TestClass.Equals(TestClass)
。
最后,other
调用重载的等式运算符达三分之一时间,其中null
= other == null
和{ {1}} = left
。现在,这最终会导致System.NullReferenceException,因为 left 为空。
要解决此编码错误,请将null
中的right
替换为null
:
other == null
或者,作为条件表达式(使用表达式主体):
other is null