更新:我下面的原始分析是不正确的......
不幸的是,我对<< 32
- C# 强制左移运算符将移位数限制为右操作数的低 5 位(涉及 64 位左操作数的移位为 6 位)的行为不正确。因此,您的原始代码在 C# 中既定义明确又正确(它在 C/C++ 中是未定义的行为)。本质上,这个移位表达式:
(this.Array[i] << shift)
相当于:
(this.Array[i] << (shift & 0x1f))
我可能仍然会更改转换以使其明确(如果没有其他原因,当我在 6 个月后查看该代码时,我不会偶然发现同样的错误分析)使用上面的而不是if (shift == 32)
检查。
原文分析:
好的,这是第二个答案。最重要的是,我认为您的原始解决方案存在一个错误,即您的位长度ImmutableBitArray
是 32 位的倍数,您将为true
2 个在最后一个Int32[]
数组元素中不同的数组返回。
例如,考虑ImmutableBitArray
位长为 32 位的不同的 s。原始Equals()
方法将对数组中的一个且仅在数组中执行移位操作Int32
- 但它将值移位 32 位,因为
int shift = 0x20 - (this.length % 0x20);
将评估为 32。
这意味着下一个测试:
if (this.Array[i] << shift != other.Array[i] << shift)
将测试(0 != 0)
,因此return false
不会执行。
我会将您的Equals()
方法更改为以下内容,这不是重大更改-我认为它可以解决上述错误并更改了其他一些与样式严格相关的内容,因此您可能没有任何兴趣. 另请注意,我实际上并没有编译和测试我的Equals()
方法,因此几乎 100% 的机会存在错误(或至少是语法错误):
public bool Equals(ImmutableBitArray other)
{
if (this.length != other.length)
{
return false;
}
int finalIndex = this.Array.Length - 1;
for (int i = 0; i < finalIndex; i++)
{
if (this.Array[i] != other.Array[i])
{
return false;
}
}
// check the last array element, making sure to ignore padding bits
int shift = 32 - (this.length % 32);
if (shift == 32) {
// the last array element has no padding bits - don't shift
shift = 0;
}
if (this.Array[finalIndex] << shift != other.Array[finalIndex] << shift)
{
return false;
}
return true;
}
请注意,严格来说,即使原始GetHashCode()
方法具有相同的缺陷,它也不会出现错误,因为即使在位长为 32 的倍数时您没有正确混合最后一个元素,equal object 仍然会返回相同的哈希码。但我仍然可能决定以相同的方式在GetHashCode()
.