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
Okay - das Problem liegt tatsächlich in der Array Implementierung von ICollection<T>.Contains
. Sie können das einfach so sehen:
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>
verwendetComparer<T>.Default
, währendDictionary<TKey, TValue>
dem Benutzer die Angabe derIComparer<T>
-Implementierung für den Vergleich von Schlüsseln ermöglicht.
Aber:
EqualityComparer<T>
und IEqualityComparer<T>
handeln sollte, nicht um Comparer<T>
und IEqualityComparer<T>
EqualityComparer<T>
angegeben wird, erscheint mir sehr unnatürlich. Die Lösung überschreibt object.Equals(object)
:
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