提问人:Oly 提问时间:9/14/2018 更新时间:9/14/2018 访问量:53
ValueType GetHashCode/Equals 实现中嵌套小数行为的说明
Explanation for nested decimals behaviour in ValueType GetHashCode/Equals implementation
问:
我对自定义结构的两个实例之间的意外失败比较感到头疼。我希望有人能指出我参考来源或文档,或者确认这是否是一个错误!
提炼问题会得到如下结果:
public readonly struct TwoDecimals
{
public readonly decimal First;
public readonly decimal Second;
public TwoDecimals(decimal first, decimal second)
{
this.First = first;
this.Second = second;
}
}
public void Main()
{
var withoutTrailingZero = new TwoDecimals(42m, 42m);
var withTrailingZero = new TwoDecimals(42.0m, 42m);
var equal = withoutTrailingZero.Equals(withTrailingZero); // true
var equalHashCodes = withoutTrailingZero.GetHashCode() == withTrailingZero.GetHashCode(); // false!
}
这是一个问题,因为如果为 true,则肯定应该返回相同的值。Equals
GetHashCode
我没有覆盖 or 中的任何一个,因此自定义结构应该获得默认实现,这可能是特定于平台的。但是在这里阅读参考来源,我看到有这样一种说法的评论:Equals
GetHashCode
ValueType
我们返回哈希码的算法有点复杂。我们寻找第一个非静态字段并得到它的 [原文如此] 哈希码。
显然这不是真的,因为尽管具有不同的位,但具有相同的哈希码。42.0m
42m
相反,似乎出于某种原因,它正在回退到使用这些位。不幸的是,这种方法是,我不确定如何找到/a 来源。extern
引用源确实具有 的实现,它使用反射来比较结构的每个字段。但首先,它执行此检查Equals
// if there are no GC references in this object we can avoid reflection
// and do a fast memcmp
if (CanCompareBits(this))
return FastEqualsCheck(thisObj, obj);
FastEqualsCheck
,大概只是比较位。就我而言,它一定没有使用这种快速检查,因为位肯定不同,但我怀疑在实现中可能会发生类似的事情。GetHashCode
我还尝试了使用 s(并且具有不同的位但相同的哈希码并被认为是“相等”)和 s 的类似情况。行为仍然不如预期,但方式不同!这一次,哈希码再次不同(并且不像该代码注释中所建议的那样,等于第一个字段的哈希码)。但是这一次,该方法返回,因此至少它是一致的。double
0.0d
-0.0d
float
Equals
false
答: 暂无答案
评论
IEquatable<TwoDecimals>