Co należy nadpisać w strukturze, aby zapewnić prawidłowe działanie równości?

Jak mówi tytuł: Czy muszę nadpisać operator ==? a co z metodą .Equals()? Coś mi umknęło?

Author: Cœur, 2009-10-01

6 answers

Przykład z 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);
   }
}
 74
Author: UpTheCreek,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2009-10-01 07:50:18

Należy również zaimplementować IEquatable. Oto fragment Framework Design Guidelines:

Zaimplementuj IEquatable na typach wartości. Obiekt.Metoda równa na typy wartości powoduje boks, a jej Domyślna implementacja nie jest zbyt efektywna, ponieważ używa refekcji. / Align = "left" / Równi mogą oferować znacznie lepszą wydajność i mogą być zaimplementowany tak, aby nie powodował boksu.

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

Postępuj zgodnie z tymi samymi wytycznymi co dla nadpisuję obiekt.Równa się, gdy wdrożenie Ieequatable.Równi. Szczegółowe informacje znajdują się w sekcji 8.7.1 wytyczne dotyczące nadpisywania obiektu.Equals

 42
Author: Dzmitry Huba,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2009-10-01 07:52:44

Niestety nie mam dość reputacji, aby komentować inne wpisy. Więc zamieszczam ewentualne ulepszenia do najlepszego rozwiązania tutaj.

Popraw mnie, jeśli się mylę, ale implementacja wspomniana wyżej

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);
   }
}
Ma poważną wadę. Odwołuję się do
  public override int GetHashCode() 
   {
      return re.GetHashCode() ^ im.GetHashCode();
   }

XORing jest symetryczny, więc złożone (2,1) i złożone(1,2) dałyby ten sam hashCode.

Powinniśmy zrobić coś bardziej jak:

  public override int GetHashCode() 
   {
      return re.GetHashCode() * 17 ^ im.GetHashCode();
   }
 12
Author: Ajk,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2013-11-21 16:35:34

Przez większość czasu można unikać implementacji Equals i GetHashcode w strukturach - ponieważ kompilator automatycznie implementuje typy wartości używając bitowych elementów content + reflection dla elementów referencyjnych.

Zobacz ten post : która jest najlepsza dla struktury/klas przechowujących dane?

Więc dla ułatwienia można jeszcze wdrożyć = = i !=.

Ale przez większość czasu można uniknąć implementacji Equals i GetHashcode.
Przypadek, w którym musisz zaimplementować równe i GetHashCode jest dla pola, którego nie chcesz nie brać pod uwagę.
Na przykład pole, które zmienia się w miarę upływu czasu, jak wiek osoby lub instantSpeed samochodu (tożsamość obiektu nie powinna się zmieniać, jeśli chcesz znaleźć go z powrotem w słowniku w tym samym miejscu)

Pozdrawiam, najlepszy kod

 9
Author: Emmanuel DURIN,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2017-05-23 12:34:26

Podstawowa różnica między tymi dwoma jest taka, że operator == jest statyczny, tzn. odpowiednia metoda do wywołania jest określana w czasie kompilacji, podczas gdy metoda Equals jest wywoływana dinamicznie na instancji.
Definiowanie obu jest prawdopodobnie najlepszą rzeczą do zrobienia, nawet jeśli ma to mniejsze znaczenie w przypadku struktur, ponieważ struktury nie mogą być rozszerzane (struktura nie może dziedziczyć po innej).

 3
Author: Paolo Tedesco,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2009-10-01 08:00:19

Tylko dla kompletności radziłbym też przeciążenie Equals Metoda:

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

Jest to prawdziwa poprawa spead, ponieważ nie występuje Boks argumentu wejściowego metody Equals(Object obj)

Niektóre najlepsze praktyki korzystania z typów wartości:

  • uczyń je niezmiennymi
  • override Equals (ten, który przyjmuje obiekt jako argument);
  • przeciążenie równa się pobraniu innej instancji tego samego typu wartości(np. * Equals (Complex other));
  • przeciążenie operatorzy = = i !=;
  • override GetHashCode

To pochodzi z tego postu: http://theburningmonk.com/2015/07/beware-of-implicit-boxing-of-value-types/

 0
Author: Tomasz Jaskuλa,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2015-07-24 15:23:51