Warum gibt Contains () false zurück, aber es wird in eine Liste eingeschlossen, und Intersect () gibt true zurück?

8

Problem:

Wenn ich Contains() für eine IEnumerable<T> von Klassen verwende, die IEquatable richtig umsetzen und GetHashCode überschreiben, wird false zurückgegeben. Wenn ich das Übereinstimmungsziel in eine Liste einschließen und ein Intersect() ausführen, funktioniert die Übereinstimmung korrekt. Ich würde lieber Contains() verwenden.

On IEnumerable.Contains() von MSDN :

  

Elemente werden mit dem angegebenen Wert verglichen, indem die Standardeinstellung Gleichheitsvergleich

On EqualityComparer<T>.Default Eigenschaft von MSDN :

  

Die Eigenschaft "Default" prüft, ob Typ T die generische System.IEquatable-Schnittstelle implementiert und, falls dies der Fall ist, einen EqualityComparer zurückgibt, der diese Implementierung verwendet. Andernfalls wird ein EqualityComparer zurückgegeben, der die von T bereitgestellten Overrides von Object.Equals und Object.GetHashCode verwendet.

Soweit ich das verstehe, sollte die Implementierung von IEquatable<T> für meine Klasse bedeuten, dass die Methode Equals vom Standardvergleich verwendet wird, wenn eine Übereinstimmung gefunden werden soll. Ich möchte Equals verwenden, weil ich möchte, dass es nur eine Möglichkeit gibt, dass zwei Objekte gleich sind. Ich möchte keine Strategie, an die sich die Entwickler erinnern müssen.

Was ich seltsam finde, ist, dass wenn ich das Match-Ziel in ein List und dann ein Intersect einbringe, die Übereinstimmung korrekt gefunden wird.

Was vermisse ich? Muss ich auch einen Gleichheitsvergleich erstellen, wie den MSDN-Artikel? MSDN schlägt vor, dass IEquatable genug ist und dass es es für mich umschließt.

Beispiel für eine Konsolenanwendung

Hinweis: GetHashCode() von Jon Skeet hier

%Vor%

.NET 4.5 Geige Beispiel

    
Dr Rob Lang 21.08.2014, 06:51
quelle

1 Antwort

7

Okay - das Problem liegt tatsächlich in der Array Implementierung von ICollection<T>.Contains . Sie können das einfach so sehen:

%Vor%

Enumerable.Contains delegiert an ICollection<T>.Contains , wenn die Quelle ICollection<T> implementiert, weshalb Sie das Array-Verhalten anstelle der Enumerable.Contains "long-hand" Implementierung in Ihrem Code erhalten haben.

Jetzt ICollection<T>.Contains sagt , dass es die Implementierung ist, um den zu verwendenden Vergleich auszuwählen:

  

Implementierungen können variieren, wie sie die Gleichheit von Objekten bestimmen; Beispiel: List<T> verwendet Comparer<T>.Default , während Dictionary<TKey, TValue> dem Benutzer die Angabe der IComparer<T> -Implementierung für den Vergleich von Schlüsseln ermöglicht.

Aber:

  • Diese Dokumentation ist bereits gebrochen, da es sich um EqualityComparer<T> und IEqualityComparer<T> handeln sollte, nicht um Comparer<T> und IEqualityComparer<T>
  • Die Entscheidung von Arrays, einen Vergleicher zu verwenden, der weder explizit noch als Standard EqualityComparer<T> angegeben wird, erscheint mir sehr unnatürlich.

Die Lösung überschreibt object.Equals(object) :

%Vor%

Es ist im Allgemeinen angenehm, aus Konsistenzgründen sowohl IEquatable<T> als auch override object.Equals(object) zu implementieren. Also während dein Code sollte schon in meiner Sicht funktionieren

    
Jon Skeet 21.08.2014, 06:58
quelle

Tags und Links