与自定义比较器不同的LinQ留下重复

时间:2009-10-25 13:48:15

标签: linq c#-3.0 distinct custom-compare

我有以下课程:

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();

但是,distinct不能做我想做的事,如下面的代码所示:

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 个答案:

答案 0 :(得分:11)

您的问题是您未正确实施IEqualityComparer

当您实施IEqualityComparer<T>时,必须实施GetHashCode,以便任何两个相等的对象具有相同的哈希码。

否则,您将看到不正确的行为,正如您在此处看到的那样。

您应该按如下方式实现GetHashCode :(由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;
}

最后,虽然您不需要,但您应该覆盖Equals中的SupplierCategory并让其调用您为Equals实施的IEquatable方法。

答案 1 :(得分:4)

实际上,这个问题甚至包含在文档中: http://msdn.microsoft.com/en-us/library/bb338049.aspx