举一个简单的例子,假设你有两个在很多方面都不同的类,但仍然可以被认为是“等同的”:
class WholeNumber: IEquatable<WholeNumber> {
int value;
public override bool Equals(object obj) {
if (obj is IEquatable<WholeNumber>) {
IEquatable<WholeNumber> other = (IEquatable<WholeNumber>) obj;
return other.Equals(this);
} else {
return false;
}
}
public bool Equals(WholeNumber other) {
return this.value == other.value;
}
}
class Fraction : IEquatable<WholeNumber> {
WholeNumber numerator;
WholeNumber denominator;
public bool Equals(WholeNumber other) {
if (denominator != 1) {
// Assume fraction is already reduced
return false;
} else {
return this.numerator.Equals(other);
}
}
}
这将允许任何声称等于WholeNumber的对象被传递到WholeNumber的Equals(对象)函数,并获得所需的结果,而WholeNumber不需要知道任何其他类。
这种模式是个好主意吗?将IEquatable与其他类一起使用是一个常见的东西(它在哪里制造)?
答案 0 :(得分:3)
不,这是一个坏主意。虽然此代码不会发生无限递归,但当您将Equals()
个实例委托给其他人时,它仍然是一个持续的威胁。 (如果你使用这种方法,那么我强烈建议编写许多单元测试,以确保Equals()
在所有情况下都能达到预期效果。)
请注意,当a.Equals((object)b)
返回true时,a.GetHashCode() == b.GetHashCode()
也必须为true。如果您无法确保new WholeNumber(2)
和new Fraction(2, 4)
具有相同的哈希码,那么它们不应该按Equals(object)
进行比较。
我采用的做法是Equals(object)
覆盖仅在参数的类型为或者从声明覆盖的类型派生时才返回true - 在本例中为obj is WholeNumber
。如果这是真的,obj.GetType() != typeof(WholeNumber)
则我会调用b.Equals(a)
,以便更多派生的Equals()
获得优先权。
如果你需要与表兄弟类型相等,那么就是IEquatable<T>
所在的地方。在这种情况下,你也会在IEquatable<Fraction>
上实现WholeNumber
,这对于委托是完全合理的到Fraction
执行IEquatable<WholeNumber>.Equals()
以避免重复该逻辑。 (提供从WholeNumber
到Fraction
的隐式转换在这里也可能是有益的。)