调用了等价比较器的GetHashCode,但是没有调用
本文关键字:调用 比较器 GetHashCode | 更新日期: 2023-09-27 17:50:32
我有两个列表,我试图比较。因此,我创建了一个实现IEqualityComparer
接口的类,请参见下面代码的底部部分。
当我通过我的代码,代码通过我的GetHashCode
实现,而不是Equals
?我并不真正理解GetHashCode
方法,尽管在互联网上阅读,它到底在做什么。
List<FactorPayoffs> missingfactorPayoffList =
factorPayoffList.Except(
factorPayoffListOrg,
new FactorPayoffs.Comparer()).ToList();
List<FactorPayoffs> 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<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;
}
}
}
您的Equals
和GetHashCode
实现应该包含完全相同的一组属性;
用更正式的术语来说,GetHashCode
必须总是为两个比较相等的对象返回相同的值。在当前的代码中,只有Ret_USD
值不同的两个对象比较起来总是相等的,但不能保证具有相同的哈希码。
所以发生的是LINQ在两个你认为相等的对象上调用GetHashCode
,得到不同的值,得出结论,因为值不同,对象不可能相等,所以调用Equals
根本没有意义,然后继续前进。
要解决这个问题,要么从GetHashCode
中删除Ret_USD
因子,要么在Equals
中引入它(无论对您的相等语义有什么意义)。
GetHashCode
旨在快速但粗略地估计相等性,因此许多可能涉及大量比较的操作从检查此结果而不是Equals
开始,并且仅在必要时使用Equals
。特别是,如果x.GetHashCode()!=y.GetHashCode()
,那么我们已经知道x.Equals(y)
是假的,所以没有理由调用Equals
。如果有x.GetHashCode()==y.GetHashCode()
,那么x
可能等于y
,但是只有调用Equals
才能得到一个确定的答案。
如果你实现GetHashCode
的方式导致GetHashCode
对两个对象不同,而Equals
返回true
,那么你的代码中有一个错误,许多依赖于这些方法的集合类和算法将默默地失败。
如果你想强制执行等号,你可以这样实现
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
是毫无意义的浪费,只是从哈希中排除。
看这里我知道的最好的通用答案,