在编写我自己的ByteArray内部使用字节数组的不可变类时,我实现了IStructuralEquatable接口.在我的实现中,我将计算哈希码的任务委托给内部数组.在测试它时,令我惊讶的是,我发现我的两个不同的数组具有相同的结构哈希码,即它们返回相同的值GetHashCode.重现:
IStructuralEquatable array11 = new int[] { 1, 1 };
IStructuralEquatable array12 = new int[] { 1, 2 };
IStructuralEquatable array22 = new int[] { 2, 2 };
var comparer = EqualityComparer<int>.Default;
Console.WriteLine(array11.GetHashCode(comparer)); // 32
Console.WriteLine(array12.GetHashCode(comparer)); // 32
Console.WriteLine(array22.GetHashCode(comparer)); // 64
Run Code Online (Sandbox Code Playgroud)
IStructuralEquatable是一个非常新的和未知的,但我在某处读到它可以用来比较集合和数组的内容.我错了,还是我的.Net错了?
请注意,我不是在谈论Object.GetHashCode!
编辑:所以,我显然是错的,因为不等对象可能有相同的哈希码.但是,不是要求GetHashCode一组有点随机分布的值作为要求吗?经过一些测试后,我发现任何两个具有相同第一个元素的数组都具有相同的哈希值.我仍然认为这是一种奇怪的行为.
Mic*_*zyk 14
你所描述的不是一个bug. GetHashCode()不保证不等对象的唯一哈希值.
来自MSDN:
如果两个对象比较相等,则每个对象的GetHashCode方法必须返回相同的值.但是,如果两个对象的比较不相等,则两个对象的GetHashCode方法不必返回不同的值.
编辑
虽然MSFT .NET实现的GetHashCode()用于Array.IStructuralEquatable在MSDN文档遵循以上的原则,看来作者并没有实现它的目的.
这是"Array.cs"中的代码:
int IStructuralEquatable.GetHashCode(IEqualityComparer comparer) {
if (comparer == null)
throw new ArgumentNullException("comparer");
Contract.EndContractBlock();
int ret = 0;
for (int i = (this.Length >= 8 ? this.Length - 8 : 0); i < this.Length; i++) {
ret = CombineHashCodes(ret, comparer.GetHashCode(GetValue(0)));
}
return ret;
}
Run Code Online (Sandbox Code Playgroud)
特别注意这一行:
ret = CombineHashCodes(ret, comparer.GetHashCode(GetValue(0)));
除非我弄错了,否则就是0这样i.因此,GetHashCode()对于具有相同max(0,n-8th)元素的数组,始终返回相同的值,其中n是数组的长度.这没有错(不违反文档),但显然没有0被替换的那样好i.如果代码只是使用数组中的单个值,也没有理由循环.
至少从 .NET 4.6.2 开始,此错误已得到修复。您可以通过Reference Source看到它。
ret = CombineHashCodes(ret, comparer.GetHashCode(GetValue(i)));
Run Code Online (Sandbox Code Playgroud)