1

簡単な例として、多くの点で異なるが「同等」とみなすことができる 2 つのクラスがあるとします。

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)whenが 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も実装し、そのロジックの重複を避けるために toの実装WholeNumberに委譲することは完全に理にかなっています。( からへの暗黙的な変換を提供すると、ここでも有益な場合があります。)FractionIEquatable<WholeNumber>.Equals()WholeNumberFraction

于 2013-08-21T22:11:26.933 に答える