IEqualityComparer正在调用GetHashCode但是Equals not
我有两个列表,我想比较。 所以我创建了一个实现IEqualityComparer
接口的类,请参见下面的代码底部。
当我单步执行代码时,代码会通过我的GetHashCode
实现而不是Equals
? 我不太了解GetHashCode
方法,尽管在互联网上阅读以及它到底在做什么。
List missingfactorPayoffList = factorPayoffList.Except( factorPayoffListOrg, new FactorPayoffs.Comparer()).ToList(); List missingfactorPayoffListOrg = factorPayoffListOrg.Except( factorPayoffList, new FactorPayoffs.Comparer()).ToList();
因此,在上面的两行代码中,两个列表返回每个项目,告诉我这两个列表不包含任何相同的项目。 事实并非如此,只有不同的行。 我猜这种情况正在发生,因为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 { 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; } } }
您的Equals
和GetHashCode
实现应该涉及完全相同的属性集; 他们不。
在更正式的术语中, GetHashCode
必须始终为两个比较相等的对象返回相同的值。 使用当前代码,两个仅在Ret_USD
值上不同的对象将始终比较相等,但不保证具有相同的哈希码。
所以会发生什么是LINQ在你认为相等的两个对象上调用GetHashCode
,得到不同的值,得出的结论是,由于值不同,对象不能相等所以在调用Equals
并继续前进时根本就没有意义。
要解决这个问题,可以从GetHashCode
删除Ret_USD
因子,也可以在Equals
引入它(对于你的相等语义都是有意义的)。
GetHashCode
旨在作为一个快速但粗略的相等估计,因此许多可能涉及大量比较的操作首先检查此结果而不是Equals
,并且仅在必要时使用Equals
。 特别是,如果x.GetHashCode()!=y.GetHashCode()
,那么我们已经知道x.Equals(y)
为false,因此没有理由调用Equals
。 如果x.GetHashCode()==y.GetHashCode()
,则x
可能等于y
,但只有对Equals
的调用才会给出明确的答案。
如果实现GetHashCode
的方式导致GetHashCode
对于Equals
返回true
两个对象不同,那么您的代码中就会出现错误,许多依赖于这些方法的集合类和算法将无声地失败。
如果要强制执行Equals,可以按如下方式实现
public int GetHashCode(FactorPayoffs obj) { return 1; }
像这样重写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; } }
请注意,您应该使用unchecked
因为您不关心溢出。 另外,合并到string.Empty
是毫无意义的浪费,只是从哈希中排除。
在这里查看我知道的最佳通用答案 ,