我已经覆盖了 Equals(对象输入)数千次,并且从未考虑过这个问题。现在,经过几次喝酒后,我开始思考它,它让我感到震惊,我不能完全确定为什么会这样。
平等操作在语义上是检查两个东西是否是自身的副本。通常,它是基于指针(参考值或任何人可能想要调用它)完成的。有时,我们希望将平等定义为例如实例 a 的某些属性的总和与实例 b 的属性相同,不一定在任何属性上相等。
但是,不同类型的两个对象不能具有相同的引用,可以吗?并且,即使两种类型具有相同的属性集(称为相同的,键入相同的属性),它仍然是苹果和橙子,因此比较将无意义(至少)或损坏逻辑。
是否有任何(我的意思是任何) Equals 操作的输入可能属于不同类型的情况,然后是仍然是有意义吗?
答案 0 :(得分:7)
你的假设是错误的:
平等操作在语义上是检查两个东西是否是自身的副本。通常,它是基于指针(参考值或任何人可能想要调用它)完成的。
那是引用相等,它由函数Object.ReferenceEquals检查(它是静态的,不可覆盖的)
对象相等性不同,您可以应用所需的规则。如果它不是那样的话,你会如何检查两个值类型(它们在C#中不能保存相同的引用)?
考虑:
int a = 5;
int b = 5;
a.Equals(b); // what would this return? `a` and `b` are different objects
现在,对于问题的第二部分,根据您的需要,可能需要将对象视为不同类型的对象。考虑:
public class Point2D {
public int X, Y;
}
public class Point3D {
public int X, Y, Z;
public override bool Equals(object source) {
var p2D = source as Point2D;
if(p2D != null)
{
if(this.Z == 0 && p2D.X == this.X && p2D.Y == this.Y)
return true;
return false;
}
//...
}
}
在这种情况下:
var p2D = new Point2D(5,5); // <-- let's pretend we have the right constructor
var p3D = new Point3D(5,5,0);
object.Equals(p3D,p2D); // <-- returns true
object.ReferenceEquals(p3D, p2D); // <-- returns false
对于性能(特别是对于值类型),您可能希望实现IEquatable<T>
或IEqualityComparer<T>
(或者更好,来自EqualityComparer<T>
),这允许直接比较特定类型(无需在之前将其包装到object
),但这超出了本答案的范围。
请注意,如果您实现此接口,仍然建议覆盖Object.Equals
,以便在两者之间匹配行为。