C # Distinct auf IEnumerable mit benutzerdefinierten IEqualityComparer
-
10-07-2019 - |
Frage
Hier ist, was ich versuche zu tun. Ich Abfrage eine XML-Datei in XML mithilfe von LINQ, die mir ein IEnumerable<T
> Objekt gibt, wo T meine „Village“ Klasse ist, mit den Ergebnissen dieser Abfrage gefüllt. Einige Ergebnisse werden dupliziert, so dass ich einen Distinct () auf dem IEnumerable-Objekt durchführen mag, etwa so:
public IEnumerable<Village> GetAllAlliances()
{
try
{
IEnumerable<Village> alliances =
from alliance in xmlDoc.Elements("Village")
where alliance.Element("AllianceName").Value != String.Empty
orderby alliance.Element("AllianceName").Value
select new Village
{
AllianceName = alliance.Element("AllianceName").Value
};
// TODO: make it work...
return alliances.Distinct(new AllianceComparer());
}
catch (Exception ex)
{
throw new Exception("GetAllAlliances", ex);
}
}
Wie der Standardvergleich nicht für das Dorf Objekt funktionieren würde, implementiert ich einen benutzerdefinierten ein, wie hier in der Klasse AllianceComparer gesehen:
public class AllianceComparer : IEqualityComparer<Village>
{
#region IEqualityComparer<Village> Members
bool IEqualityComparer<Village>.Equals(Village x, Village y)
{
// Check whether the compared objects reference the same data.
if (Object.ReferenceEquals(x, y))
return true;
// Check whether any of the compared objects is null.
if (Object.ReferenceEquals(x, null) || Object.ReferenceEquals(y, null))
return false;
return x.AllianceName == y.AllianceName;
}
int IEqualityComparer<Village>.GetHashCode(Village obj)
{
return obj.GetHashCode();
}
#endregion
}
Die Distinct () Methode nicht funktioniert, wie ich genau die gleiche Anzahl von Ergebnissen mit oder ohne sie. Eine andere Sache, und ich weiß nicht, ob es in der Regel möglich ist, aber ich kann nicht Schritt in AllianceComparer.Equals (), um zu sehen, was das Problem sein könnte.
Ich habe Beispiele dafür im Internet zu finden, aber ich kann nicht scheinen, um meine Implementierung Arbeit zu machen.
Ich hoffe, jemand hier vielleicht sehen, was hier falsch sein könnte! Vielen Dank im Voraus!
Lösung
Das Problem ist, mit Ihrem GetHashCode
. Sie sollten es ändern, anstatt den Hash-Code von AllianceName
zurückzukehren.
int IEqualityComparer<Village>.GetHashCode(Village obj)
{
return obj.AllianceName.GetHashCode();
}
Die Sache ist, wenn Equals
kehrt true
, sollten die Objekte haben den gleichen Hash-Code, der nicht der Fall für verschiedene Village
Objekte mit gleichen AllianceName
ist. Da Distinct
intern durch den Bau einer Hash-Tabelle funktioniert, werden Sie sich mit gleichen Objekten beenden, die überhaupt auf verschiedene Hash-Codes aufgrund wird nicht abgestimmt.
In ähnlicher Weise zwei Dateien zu vergleichen, wenn der Hash aus zwei Dateien sind nicht die gleichen, Sie brauchen nicht die Dateien zu überprüfen gar selbst. Sie unterschiedlich sein. Andernfalls werden Sie auch weiterhin überprüfen, um zu sehen, ob sie wirklich gleich sind oder nicht. Das ist genau das, was die Hash-Tabelle, die verhält sie Distinct
verwendet.
Andere Tipps
return alliances.Select(v => v.AllianceName).Distinct();
Das wäre eine IEnumerable<string>
statt IEnumerable<Village>
zurück.
oder ändern Sie die Zeile
return alliances.Distinct(new AllianceComparer());
return alliances.Select(v => v.AllianceName).Distinct();