Linq Except 如何比较结果

How does Linq Except Compare results

Except如何判断2个值是否相同

我有以下代码

var removes = collection.Except(values, comparer).ToList();
var adds = values.Except( collection, comparer).ToList();
foreach (var item in removes)
{
    collection.Remove(item);
}
foreach (var item in adds)
{
    collection.Add(item);
}

然而,比较器认为相等的项目包含在例外列表中,所以为了查看发生了什么,我在 Equals 函数中放置了一个断点并且它没有被调用,只有 GetHashCode() 函数

那么用什么标准来比较项目,是不是只有哈希值不同才调用相等函数?

编辑: 比较器 Class 和比较器 class 是

public class Lookup
{
    public static readonly IEqualityComparer<Lookup> DefaultComparer = new EqualityComparer();
    private class EqualityComparer : IEqualityComparer<Lookup>
    {
        public bool Equals(Lookup x, Lookup y)
        {
            if (x == null)
                return y == null;
            else if (y == null)
                return false;
            else
                return x.ID == y.ID
                    && x.Category == y.Category
                    && x.DisplayText == y.DisplayText
                    && MetaData.CollectionComparer.Equals(x.MetaData, y.MetaData);
        }

        public int GetHashCode(Lookup obj)
        {
            var rtn = new { obj.ID, obj.Category, obj.DisplayText, obj.MetaData }.GetHashCode();

            return rtn;
        }
    }
    [DataMember]
    public int ID { get; set; }
    [DataMember]
    public LookupType Category { get; set; }
    [DataMember]
    public string DisplayText { get; set; }
    [DataMember]
    public MetaData[] MetaData { get; set; }
}

问题是你的比较器的实现。在等于你有

...
&& MetaData.CollectionComparer.Equals(x.MetaData, y.MetaData);

但是在 GetHashCode 中你有

new { ..., obj.MetaData }.GetHashCode();

这意味着它对哈希码使用默认比较器,但对等号使用 MetaData.CollectionComparer。这导致事物具有 MetaData.CollectionComparer.Equals(x.MetaData, y.MetaData) == true 到 return 不同的哈希码,这些哈希码会破坏基于 Set 逻辑的任何东西(.Exclude( 使用)。

将使用匿名 class 的散列码 hack 替换为使用 MetaData.CollectionComparer.GetHashCode(obj.MetaData) 的实际散列码实现,它应该可以工作。

public int GetHashCode(Lookup obj)
{
    unchecked
    {
        var hashCode = obj.ID;
        hashCode = (hashCode*397) ^ (obj.Category != null ? obj.Category.GetHashCode() : 0);
        hashCode = (hashCode*397) ^ (obj.DisplayText != null ? obj.DisplayText.GetHashCode() : 0);
        hashCode = (hashCode*397) ^ MetaData.CollectionComparer.GetHashCode(obj.MetaData);
        return hashCode;
    }
}

(此实现是 ReSharper 提出的,经过调整以使用 MetaData.CollectionComparer

is it only if the hashes are different that it calls the equality function?

是的,就是这样。这是出于性能原因(假设 GetHashCode 实施应始终比 Equals 实施快得多)。

如果两个对象有不同的哈希码,它们肯定不会是相同的相等的对象,所以没有需要打电话给 Equals。仅当哈希码相同时,才会调用 Equals 以查看它们是否真的相等或只是偶然具有相同的哈希码。

因此您的 GetHashCode 实施应始终确保 相等 个对象具有相同的哈希码。

由于您对 GetHashCode 的实现创建了一个匿名类型的实例并在该实例上调用 GetHashCode,因此哈希码将始终不同,因此您的所有对象都彼此不同。