Что необходимо переопределить в структуре, чтобы обеспечить правильное функционирование равенства? - PullRequest
68 голосов
/ 01 октября 2009

Как видно из заголовка: мне нужно переопределить оператор ==? как насчет метода .Equals()? Что-то мне не хватает?

Ответы [ 6 ]

80 голосов
/ 01 октября 2009

Пример из MSDN

public struct Complex 
{
   double re, im;
   public override bool Equals(Object obj) 
   {
      return obj is Complex && this == (Complex)obj;
   }
   public override int GetHashCode() 
   {
      return re.GetHashCode() ^ im.GetHashCode();
   }
   public static bool operator ==(Complex x, Complex y) 
   {
      return x.re == y.re && x.im == y.im;
   }
   public static bool operator !=(Complex x, Complex y) 
   {
      return !(x == y);
   }
}
43 голосов
/ 01 октября 2009

Вы также должны реализовать IEquatable . Вот выдержка из Руководства по проектированию фреймворка:

СЛЕДУЕТ реализовывать IEquatable для типов значений. Метод Object.Equals для типов значений вызывает бокс и его реализация по умолчанию не очень эффективна, потому что она использует усовершенствование. IEquatable.Equals может предложить гораздо лучшую производительность и может быть реализован так, чтобы не вызывать бокс.

public struct Int32 : IEquatable<Int32> {
    public bool Equals(Int32 other){ ... }
}

НУЖНО следовать тем же правилам, что и для переопределение Object.Equals когда реализации IEquatable.Equals. См. Раздел 8.7.1 для подробного руководство по переопределению Object.Equals

14 голосов
/ 21 ноября 2013

К сожалению, у меня недостаточно репутации, чтобы комментировать другие записи. Так что я публикую здесь возможное улучшение топ-решения.

Поправьте меня, если я не прав, но реализация упомянута выше

public struct Complex 
{
   double re, im;
   public override bool Equals(Object obj) 
   {
      return obj is Complex && this == (Complex)obj;
   }
   public override int GetHashCode() 
   {
      return re.GetHashCode() ^ im.GetHashCode();
   }
   public static bool operator ==(Complex x, Complex y) 
   {
      return x.re == y.re && x.im == y.im;
   }
   public static bool operator !=(Complex x, Complex y) 
   {
      return !(x == y);
   }
}

Имеет большой недостаток. Я ссылаюсь на

  public override int GetHashCode() 
   {
      return re.GetHashCode() ^ im.GetHashCode();
   }

XORing является симметричным, поэтому Complex (2,1) и Complex (1,2) будут иметь одинаковый хэш-код.

Мы, вероятно, должны сделать что-то вроде:

  public override int GetHashCode() 
   {
      return re.GetHashCode() * 17 ^ im.GetHashCode();
   }
9 голосов
/ 26 сентября 2015

Большую часть времени вы можете избежать реализации Equals и GetHashcode в структурах - потому что компилятор автоматически реализует типы значений с использованием побитового содержимого + отражения для ссылочных членов.

Посмотрите на этот пост: Что лучше всего подходит для хранилища данных Struct / Classes?

Так что для простоты использования вы все равно можете использовать == и! =.

Но большую часть времени вы можете избежать реализации Equals и GetHashcode.
Случай, когда вам нужно реализовать Equals и GetHashCode, относится к полю, которое вы не хотите принимать во внимание.
Например, поле, которое меняется с течением времени, например, возраст человека или мгновенная скорость автомобиля (идентичность объекта не должна изменяться, если вы хотите найти его в словаре в том же месте)

С уважением, лучший код

3 голосов
/ 01 октября 2009

Основное различие между ними состоит в том, что оператор == является статическим, т. Е. Соответствующий метод для вызова определяется во время компиляции, тогда как метод Equals вызывается динамически в экземпляре.
Определение обоих, вероятно, лучше всего сделать, даже если это имеет меньшее значение в случае структур, поскольку структуры не могут быть расширены (структура не может наследовать от другой).

0 голосов
/ 24 июля 2015

Просто для полноты я бы также советовал перегрузить Equals метод:

public bool Equals(Complex other) 
{
   return other.re == re && other.im == im;
}

это реальное улучшение скорости, так как в аргументе ввода Equals(Object obj) метода

не происходит бокс

Некоторые рекомендации по использованию типов значений:

  • сделать их неизменными
  • переопределить Equals (тот, который принимает объект в качестве аргумента);
  • перегрузка Равно для получения другого экземпляра того же типа значения (например, * Равно (Комплексное другое));
  • операторы перегрузки == и! =;
  • переопределить GetHashCode

Это из этого поста: http://theburningmonk.com/2015/07/beware-of-implicit-boxing-of-value-types/

...