C# Linq如何比较结果

C# Linq如何比较结果,c#,linq,iequalitycomparer,C#,Linq,Iequalitycomparer,Except如何确定两个值是否相同 我有以下代码 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.

Except如何确定两个值是否相同

我有以下代码

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函数

那么,用来比较项目的标准是什么呢?是否只有当散列值不同时,才会调用相等函数

编辑: comparer类和compared类是

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);
new { ..., obj.MetaData }.GetHashCode();
但是在GetHashCode中

...
&& MetaData.CollectionComparer.Equals(x.MetaData, y.MetaData);
new { ..., obj.MetaData }.GetHashCode();
这意味着它对哈希代码使用默认比较器,而对相等代码使用MetaData.CollectionComparer。这导致MetaData.CollectionComparer.Equalsx.MetaData,y.MetaData==true的内容返回不同的哈希代码,该哈希代码根据.Exclude使用的集合逻辑中断任何内容

用使用MetaData.CollectionComparer.GetHashCodeobj.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提出的,经过调整以使用元数据。CollectionComparer

问题在于比较器的实现。和你一样

...
&& MetaData.CollectionComparer.Equals(x.MetaData, y.MetaData);
new { ..., obj.MetaData }.GetHashCode();
但是在GetHashCode中

...
&& MetaData.CollectionComparer.Equals(x.MetaData, y.MetaData);
new { ..., obj.MetaData }.GetHashCode();
这意味着它对哈希代码使用默认比较器,而对相等代码使用MetaData.CollectionComparer。这导致MetaData.CollectionComparer.Equalsx.MetaData,y.MetaData==true的内容返回不同的哈希代码,该哈希代码根据.Exclude使用的集合逻辑中断任何内容

用使用MetaData.CollectionComparer.GetHashCodeobj.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

是否只有当哈希值不同时,它才会调用相等函数

是的,就是这样。这是出于性能原因,假设GetHashCode实现应该总是比Equals实现快得多

如果两个对象具有不同的哈希代码,那么它们肯定不是相同或相等的对象,因此不需要调用Equals。只有当散列码相同时,才会调用Equals来查看它们是否真的相等,或者只是碰巧拥有相同的散列码

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

由于GetHashCode的实现创建了一个匿名类型的实例,并在该实例上调用GetHashCode,因此哈希代码总是不同的,因此所有对象都是不同的

是否只有当哈希值不同时,它才会调用相等函数

是的,就是这样。这是出于性能原因,假设GetHashCode实现应该总是比Equals实现快得多

如果两个对象具有不同的哈希代码,那么它们肯定不是相同或相等的对象,因此不需要调用Equals。只有当散列码相同时,才会调用Equals来查看它们是否真的相等,或者只是碰巧拥有相同的散列码

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


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

如果两个对象相等,它们应该在GetHashCode中返回相同的值。如果您正确地实现Equals和GetHashCode,它的工作方式应该无关紧要,而且两个相等的对象必须返回相同的哈希代码。不仅应该如此。如果两个对象相等,它们应该在GetHashCode中返回相同的值。看一看:或者这里:发布comparer的实现。如果您正确地实现Equals和GetHashCode,它的工作方式应该无关紧要,而且两个相等的对象必须返回相同的哈希代码。不仅仅是应该。对于记录,关于如何修复哈希算法,您可能是正确的,但这不是所问的问题,我需要了解linq如何执行比较以避免将来犯这些错误。我说,这会导致出现元数据。CollectionComparer.Equalsx.MetaData,y.MetaData==返回不同的散列码,该散列码根据.Exclude使用的集合逻辑断开任何内容。此外,您可以始终检查msdn页,您将看到通过使用指定的IEqualityComparer比较值来生成两个序列的集合差。,如果检查接口,您将看到必须实现Equals和GetHashCode。如果您查看了GetHashCode实现的文档,则需要
d以确保如果Equals方法为两个对象x和y返回true,那么,GetHashCode方法为x返回的值必须等于为y返回的值……您的实现违反了该约定,因此您不能依靠任何使用IEqualityComparer的方法来正确工作。对于记录,您可能正确地了解了如何修复哈希算法,但这不是所问的问题,我需要了解linq如何执行比较以避免将来犯这些错误我说,这会导致具有MetaData.CollectionComparer.Equalsx.MetaData,y.MetaData==true的内容返回不同的哈希代码,该代码会破坏基于集合逻辑的任何内容。排除使用,您可以始终检查msdn页面,您将看到通过使用指定的IEqualityComparer比较值来生成两个序列的集差。如果您检查接口,您将看到您必须实现Equals和GetHashCode。如果检查GetHashCode实现的文档,则需要确保如果Equals方法为两个对象x和y返回true,那么,GetHashCode方法为x返回的值必须等于为y返回的值……您的实现违反了该约定,因此您不能依赖任何使用IEqualityComparer的方法来正确工作。