LinQ отличается от пользовательского компаратора оставляет дубликаты - PullRequest
9 голосов
/ 25 октября 2009

У меня есть следующие классы:

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

Я использую это неправильно? почему они не сравниваются, как я намереваюсь?

Edit: Чтобы продемонстрировать, что компаратор работает, следующее возвращает 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 ]

11 голосов
/ 25 октября 2009

Ваша проблема в том, что вы неправильно реализовали IEqualityComparer.

При реализации IEqualityComparer<T> вы должны реализовать GetHashCode, чтобы любые два равных объекта имели одинаковый хеш-код.

В противном случае вы получите неправильное поведение, как вы видите здесь.

Вы должны реализовать GetHashCode следующим образом: (любезно этот ответ )

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;
}

Наконец, хотя вам это не нужно, вам, вероятно, следует переопределить Equals в SupplierCategory и заставить его вызывать метод Equals, который вы реализовали для IEquatable.

4 голосов
/ 03 ноября 2009

На самом деле, эта проблема даже описана в документации: http://msdn.microsoft.com/en-us/library/bb338049.aspx.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...