2013-08-21 1 views
1

Для простого примера, предположим, у вас есть два класса, которые отличаются во многих отношениях, но все-таки можно считать «equateable»:При переопределении Object.Equals целесообразно использовать переданные в Equal (MyType) объекты?

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

Это позволит любой объект, который утверждает, что equateable в WholeNumber будет принят в функцию Equals (object) WholeNumber и получить желаемый результат без WholeNumber, который должен знать о любом другом классе.

Этот шаблон является хорошей идеей? Использует IEquatable с другими классами обычную (где это делает) вещь?

+0

Пожалуйста, сделайте соответствующие проверки нуль в коде, а также чеки рекурсии;) –

+0

Почему бы не создать номер класса называется и есть два класса вытекают из этого? Тогда вы можете иметь Number, реализующий IEquatable. – mc10

ответ

3

Нет, это плохая идея. Хотя с этим кодом не происходит бесконечная рекурсия, это постоянная угроза, когда у вас есть некоторые случаи делегирования Equals() другим. (Если вы используете этот подход, то я настоятельно рекомендую писать много модульных тестов, чтобы убедиться, что Equals() делает то, что вы ожидаете, во всех случаях.)

Обратите внимание, что когда a.Equals((object)b) возвращает истину, a.GetHashCode() == b.GetHashCode() должны также быть правдой. Если вы не можете гарантировать, что 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 может быть полезным и здесь.)

+0

Подождите, obj отбрасывается в IEquateable , а 'this' является' WholeNumber', поэтому следует использовать 'Equals (WholeNumber)'. – Cemafor

+0

Да, разрешение перегрузки экономит вас здесь, и вы не получаете бесконечной рекурсии. Тем не менее я согласен, что это плохая идея. – Odrade

+1

Хорошая точка в отношении отношений Equals-GetHashCode. –