简体   繁体   English

重写Object.Equals时,是否适合使用传入的对象的Equals(MyType)?

[英]When overriding Object.Equals, is it appropriate to use the passed in object's Equals(MyType)?

For a simple example, assume you have two classes that are different in many ways, but can still be considered "equateable": 举一个简单的例子,假设你有两个在很多方面都不同的类,但仍然可以被认为是“等同的”:

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

This will allow any object that claims to be equateable to WholeNumber to be passed into the WholeNumber's Equals(object) function and get the desired result without WholeNumber needed to know about any other class. 这将允许任何声称等于WholeNumber的对象被传递到WholeNumber的Equals(对象)函数,并获得所需的结果,而WholeNumber不需要知道任何其他类。

Is this pattern a good idea? 这种模式是个好主意吗? Is using IEquatable with other classes a common (where it makes sence) thing to do? 是否将IEquatable与其他类一起使用是常见的(在哪里发生)要做的事情?

No, this is a bad idea. 不,这是一个坏主意。 While infinite recursion does not happen with this code, it is a constant threat when you have some instances of Equals() delegating to others. 虽然此代码不会发生无限递归,但当您将一些Equals()实例委托给其他人时,它是一个持续的威胁。 (If you use this approach then I'd strongly suggest writing many unit tests to make sure that Equals() does what you expect in all cases.) (如果你使用这种方法,那么我强烈建议编写许多单元测试,以确保Equals()在所有情况下都能达到预期效果。)

Note that when a.Equals((object)b) returns true, a.GetHashCode() == b.GetHashCode() must also be true. 请注意,当a.Equals((object)b)返回true时, a.GetHashCode() == b.GetHashCode()也必须为true。 If you cannot ensure that new WholeNumber(2) and new Fraction(2, 4) have the same hash code, then they should not compare as equal by Equals(object) . 如果您无法确保new WholeNumber(2)new Fraction(2, 4)具有相同的哈希码,那么它们不应该通过Equals(object)进行比较

The practice I have adopted is that the Equals(object) override only returns true if the argument's type is or derives from the type where the override is declared -- in this case, obj is WholeNumber . 我采用的做法是,如果参数的类型是或者从声明覆盖的类型派生,则Equals(object)覆盖仅返回true - 在这种情况下, obj is WholeNumber If this is true but obj.GetType() != typeof(WholeNumber) then I do call b.Equals(a) so that the more-derived Equals() gets priority. 如果这是真的但obj.GetType() != typeof(WholeNumber)然后我调用b.Equals(a)以便更多派生的Equals()获得优先级。

If you need equality with cousin types, then that is where IEquatable<T> comes in. In this case you would implement IEquatable<Fraction> on WholeNumber too, and it would make perfect sense to delegate to Fraction 's implementation of IEquatable<WholeNumber>.Equals() to avoid duplicating that logic. 如果你需要与堂兄类型相等,那么这就是IEquatable<T>用武之地。在这种情况下你也可以在WholeNumber上实现IEquatable<Fraction> ,并且委托给FractionIEquatable<WholeNumber>.Equals()的实现是IEquatable<WholeNumber>.Equals()以避免重复该逻辑。 (Providing an implicit conversion from WholeNumber to Fraction might be beneficial here, too.) (提供从WholeNumberFraction的隐式转换在这里也可能是有益的。)

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM