LinQ отличается от пользовательского компаратора оставляет дубликаты
У меня есть следующие классы:
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
}
И я использую следующий запрос linq:
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();
Но отличное не делает то, что я хочу, как демонстрирует следующий код:
comp.Equals(categoryPaths[0], categoryPaths[1]); //returns True
Я использую это неправильно? почему они не сравниваются, как я намереваюсь?
Редактировать: чтобы продемонстрировать, как работает компаратор, следующее возвращает true, как и должно:
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());
2 ответа
Your problem is that you didn't implement IEqualityComparer
правильно.
Когда вы реализуете IEqualityComparer<T>
, you must implement GetHashCode
так что любые два равных объекта имеют одинаковый хеш-код.
Otherwise, you will get incorrect behavior, as you're seeing here.
You should implement GetHashCode as follows: (courtesy of this answer)
public int GetHashCode(List<SupplierCategory> obj) {
int hash = 17;
foreach(var value in obj)
hash = hash * 23 + obj.GetHashCode();
return hash;
}
Вы также должны переопределить GetHashCode
в SupplierCategory
быть последовательным. Например:
public override int GetHashCode() {
int hash = 17;
hash = hash * 23 + Name.GetHashCode();
hash = hash * 23 + Parent.GetHashCode();
return hash;
}
Finally, although you don't need to, you should probably override Equals
в SupplierCategory
and make it call the Equals
method you implemented for IEquatable
,
На самом деле, эта проблема даже описана в документации: http://msdn.microsoft.com/en-us/library/bb338049.aspx.