LinQ distinct avec des feuilles de comparaison personnalisées
-
06-07-2019 - |
Question
J'ai les cours suivants:
public class SupplierCategory : IEquatable<SupplierCategory>
{
public string Name { get; set; }
public string Parent { get; set; }
#region IEquatable<SupplierCategory> Members
public bool Equals(SupplierCategory other)
{
return this.Name == other.Name && this.Parent == other.Parent;
}
#endregion
}
public class CategoryPathComparer : IEqualityComparer<List<SupplierCategory>>
{
#region IEqualityComparer<List<SupplierCategory>> Members
public bool Equals(List<SupplierCategory> x, List<SupplierCategory> y)
{
return x.SequenceEqual(y);
}
public int GetHashCode(List<SupplierCategory> obj)
{
return obj.GetHashCode();
}
#endregion
}
Et j'utilise la requête linq suivante:
CategoryPathComparer comparer = new CategoryPathComparer();
List<List<SupplierCategory>> categoryPaths = (from i in infoList
select
new List<SupplierCategory>() {
new SupplierCategory() { Name = i[3] },
new SupplierCategory() { Name = i[4], Parent = i[3] },
new SupplierCategory() { Name = i[5], Parent = i[4] }}).Distinct(comparer).ToList();
Mais le distinct ne fait pas ce que je veux, comme le montre le code suivant:
comp.Equals(categoryPaths[0], categoryPaths[1]); //returns True
Est-ce que j'utilise ceci de manière incorrecte? pourquoi ne sont-ils pas comparés comme je le souhaite?
Modifier: Pour démontrer que le comparateur fonctionne, les éléments suivants sont vrais, comme il se doit:
List<SupplierCategory> list1 = new List<SupplierCategory>() {
new SupplierCategory() { Name = "Cat1" },
new SupplierCategory() { Name = "Cat2", Parent = "Cat1" },
new SupplierCategory() { Name = "Cat3", Parent = "Cat2" }
};
List<SupplierCategory> list1 = new List<SupplierCategory>() {
new SupplierCategory() { Name = "Cat1" },
new SupplierCategory() { Name = "Cat2", Parent = "Cat1" },
new SupplierCategory() { Name = "Cat3", Parent = "Cat2" }
};
CategoryPathComparer comp = new CategoryPathComparer();
Console.WriteLine(comp.Equals(list1, list2).ToString());
La solution
Votre problème est que vous n'avez pas implémenté IEqualityComparer
correctement.
Lorsque vous implémentez IEqualityComparer<T>
, vous doit mettre en œuvre GetHashCode
de sorte que deux les objets ont le même hashcode.
Sinon, vous obtiendrez un comportement incorrect, comme vous le voyez ici.
Vous devez implémenter GetHashCode de la manière suivante: (avec l'aimable autorisation de cette réponse )
public int GetHashCode(List<SupplierCategory> obj) {
int hash = 17;
foreach(var value in obj)
hash = hash * 23 + obj.GetHashCode();
return hash;
}
Vous devez également remplacer SupplierCategory
dans Equals
pour être cohérent. Par exemple:
public override int GetHashCode() {
int hash = 17;
hash = hash * 23 + Name.GetHashCode();
hash = hash * 23 + Parent.GetHashCode();
return hash;
}
Enfin, bien que vous n'en ayez pas besoin, vous devez probablement remplacer IEquatable
dans <=> et lui demander d'appeler la méthode <=> que vous avez implémentée pour <=>.
Autres conseils
En fait, ce problème est même traité dans la documentation: http://msdn.microsoft.com/en-us/library/bb338049. aspx .