1

举一个简单的例子,假设你有两个在很多方面都不同的类,但仍然可以被认为是“等价的”:

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(object) 函数中,并获得所需的结果,而无需 WholeNumber 了解任何其他类。

这种模式是个好主意吗?将 IEquatable 与其他类一起使用是一件常见的事情吗?

4

1 回答 1

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>on ,并且将其委托给' 的实现以避免重复该逻辑WholeNumber是非常有意义的。(在这里提供从to的隐式转换也可能是有益的。)FractionIEquatable<WholeNumber>.Equals()WholeNumberFraction

于 2013-08-21T22:11:26.933 回答