Linq除了比较结果之外怎么做?

时间:2016-03-16 16:12:13

标签: c# linq iequalitycomparer

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

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

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

编辑: 比较器类和比较类是

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

2 个答案:

答案 0 :(得分:2)

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

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

然而在GetHashCode中你有

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

这意味着它使用默认比较器作为哈希码,但MetaData.CollectionComparer表示等于。这导致MetaData.CollectionComparer.Equals(x.MetaData, y.MetaData) == true的东西返回不同的哈希码,这些哈希码基于Set逻辑(.Exclude(使用)来破坏任何内容。

使用MetaData.CollectionComparer.GetHashCode(obj.MetaData)替换使用匿名类和实际哈希代码实现的哈希码hack,它应该可以工作。

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

答案 1 :(得分:1)

  

只有当哈希值不同时才会调用相等函数吗?

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

如果两个对象具有不同的哈希码,则它们肯定不会是相同的相等的对象,因此无需调用{{1 }}。只有当哈希码相同时,Equals才会被调用以查看它们是否真的相同或者只是偶然拥有相同的哈希码。

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

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