简体   繁体   English

IEqualityComparer正在调用GetHashCode,但不是Equals

[英]IEqualityComparer GetHashCode being called but Equals not

I have two lists that I am trying to compare. 我有两个列表,我想比较。 So I have created a class that implements the IEqualityComparer interface, please see below in the bottom section of code. 所以我创建了一个实现IEqualityComparer接口的类,请参见下面的代码底部。

When I step through my code, the code goes through my GetHashCode implementation but not the Equals ? 当我单步执行代码时,代码会通过我的GetHashCode实现而不是Equals I do not really understand the GetHashCode method, despite reading around on the internet and what exactly it is doing. 我不太了解GetHashCode方法,尽管在互联网上阅读以及它到底在做什么。

List<FactorPayoffs> missingfactorPayoffList = 
    factorPayoffList.Except(
        factorPayoffListOrg,
        new FactorPayoffs.Comparer()).ToList();

List<FactorPayoffs> missingfactorPayoffListOrg =
    factorPayoffListOrg.Except(
        factorPayoffList,
        new FactorPayoffs.Comparer()).ToList();

So in the two lines of code above the two lists return me every item, telling me that the two lists do not contain any items that are the same. 因此,在上面的两行代码中,两个列表返回每个项目,告诉我这两个列表不包含任何相同的项目。 This is not true, there is only row that is different. 事实并非如此,只有不同的行。 I'm guessing this is happening because the Equals method is not getting called which in turns makes me wonder if my GetHashCode method is working as its supposed to? 我猜这种情况正在发生,因为Equals方法没有被调用,这反过来让我想知道我的GetHashCode方法是否正常工作?

class FactorPayoffs
    {
        public string FactorGroup { get; set; }
        public string Factor { get; set; }
        public DateTime dtPrice { get; set; }
        public DateTime dtPrice_e { get; set; }
        public double Ret_USD { get; set; }

        public class Comparer : IEqualityComparer<FactorPayoffs>
        {
            public bool Equals(FactorPayoffs x, FactorPayoffs y)
            {                    
                return x.dtPrice == y.dtPrice && 
                    x.dtPrice_e == y.dtPrice_e && 
                    x.Factor == y.Factor && 
                    x.FactorGroup == y.FactorGroup;
            }

            public int GetHashCode(FactorPayoffs obj)
            {
                int hash = 17;
                hash = hash * 23 + (obj.dtPrice).GetHashCode();
                hash = hash * 23 + (obj.dtPrice_e).GetHashCode();
                hash = hash * 23 + (obj.Factor ?? "").GetHashCode();
                hash = hash * 23 + (obj.FactorGroup ?? "").GetHashCode();
                hash = hash * 23 + (obj.Ret_USD).GetHashCode();
                return hash;
            }
        }
    }

Your Equals and GetHashCode implementations should involve the exact same set of properties; 您的EqualsGetHashCode实现应该涉及完全相同的属性集; they do not. 他们不。

In more formal terms, GetHashCode must always return the same value for two objects that compare equal. 在更正式的术语中, GetHashCode 必须始终为两个比较相等的对象返回相同的值。 With your current code, two objects that differ only in the Ret_USD value will always compare equal but are not guaranteed to have the same hash code. 使用当前代码,两个仅在Ret_USD值上不同的对象将始终比较相等,但不保证具有相同的哈希码。

So what happens is that LINQ calls GetHashCode on two objects you consider equal, gets back different values, concludes that since the values were different the objects cannot be equal so there's no point at all in calling Equals and moves on. 所以会发生什么是LINQ在你认为相等的两个对象上调用GetHashCode ,得到不同的值,得出的结论是,由于值不同,对象不能相等所以在调用Equals并继续前进时根本就没有意义。

To fix the problem, either remove the Ret_USD factor from GetHashCode or introduce it also inside Equals (whatever makes sense for your semantics of equality). 要解决这个问题,可以从GetHashCode删除Ret_USD因子,也可以在Equals引入它(对于你的相等语义都是有意义的)。

GetHashCode is intended as a fast but rough estimate of equality, so many operations potentially involving large numbers of comparisons start by checking this result instead of Equals , and only use Equals when necessary. GetHashCode旨在作为一个快速但粗略的相等估计,因此许多可能涉及大量比较的操作首先检查此结果而不是Equals ,并且仅在必要时使用Equals In particular, if x.GetHashCode()!=y.GetHashCode() , then we already know x.Equals(y) is false, so there is no reason to call Equals . 特别是,如果x.GetHashCode()!=y.GetHashCode() ,那么我们已经知道x.Equals(y)为false,因此没有理由调用Equals Had x.GetHashCode()==y.GetHashCode() , then x might equal y , but only a call to Equals will give a definite answer. 如果x.GetHashCode()==y.GetHashCode() ,则x 可能等于y ,但只有对Equals的调用才会给出明确的答案。

If you implement GetHashCode in a way that causes GetHashCode to be different for two objects where Equals returns true , then you have a bug in your code and many collection classes and algorithms relying on these methods will silently fail. 如果实现GetHashCode的方式导致GetHashCode对于Equals返回true两个对象不同,那么您的代码中就会出现错误,许多依赖于这些方法的集合类和算法将无声地失败。

If you want to force the execution of the Equals you can implement it as follows 如果要强制执行Equals,可以按如下方式实现

public int GetHashCode(FactorPayoffs obj) {
        return 1;
    }

Rewrite you GetHashCode implementation like this, to match the semantics of your Equals implementation. 像这样重写GetHashCode实现,以匹配Equals实现的语义。

public int GetHashCode(FactorPayoffs obj)
{
    unchecked
    {
            int hash = 17;
            hash = hash * 23 + obj.dtPrice.GetHashCode();
            hash = hash * 23 + obj.dtPrice_e.GetHashCode();
            if (obj.Factor != null)
            {
                hash = hash * 23 + obj.Factor.GetHashCode();
            }

            if (obj.FactorGroup != null)
            {
                hash = hash * 23 + obj.FactorGroup.GetHashCode();
            }

            return hash;
    }
}

Note, you should use unchecked because you don't care about overflows. 注意,您应该使用unchecked因为您不关心溢出。 Additionaly, coalescing to string.Empty is pointlessy wasteful, just exclude from the hash. 另外,合并到string.Empty是毫无意义的浪费,只是从哈希中排除。

See here for the best generic answer I know , 在这里查看我知道的最佳通用答案

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM