此代码块中代字号的目的是什么?
public override int GetHashCode()
{
return ~this.DimensionId.Id ^ this.ElementId.Id;
}
^运算符(C#参考) Visual Studio 2010 二元^运算符是为整数类型和bool预定义的。对于整数类型,^计算其操作数的按位异或。对于bool操作数,^计算其操作数的逻辑异或;也就是说,当且仅当其中一个操作数为真时,结果才为真。
〜运算符(C#参考) Visual Studio 2010 〜运算符对其操作数执行按位补码运算,具有反转每个位的效果。对于int,uint,long和ulong,预定义了按位补码运算符。
〜(代字号)运算符对其单个整数操作数执行按位补码。 (因此〜运算符是一元运算符,如!和一元 - ,&和*运算符。)补码表示将所有0位更改为1,将所有1更改为0
为什么会在这种情况下使用它(而不是简单地排除它)会是什么原因?
答案 0 :(得分:13)
这只是生成哈希码的一种方法。我不是散列码中XOR的忠实粉丝,除非你想要一些与顺序无关的东西,但这是以合理的任意但可重复的方式翻转位的合理方式。
基本上你在这里有两个32位值,你需要以某种形式组合以创建另一个32位值。代码可能只是将值一起进行异或,而没有任何按位补码:
return DimensionId.Id ^ ElementId.Id;
...但对于ElementId.Id == DimensionId.Id
的情况,这总是会给出零,这可能并不理想。另一方面,如果两个ID相同,我们现在总是以-1结尾,如注释(doh!)中所述。另一方面,它使{{4,4}对具有与{4,6}不同的哈希码,而简单的XOR不...它使得排序很重要,换句话说。同样,如果您的真实标识符可能来自相对较小的池,那么这可能很重要。
XOR本身确保对 ID中的任何位的更改会对最终的哈希码产生影响。
就我个人而言,我通常会遵循Josh Bloch的有效Java模式,例如
unchecked
{
int hash = 17;
hash = hash * 31 + DimensionId.Id;
hash = hash * 31 + ElementId.Id;
return hash;
}
...但这只是因为散列的一些属性 1 ,并且它不会使你在任何意义上显示“错误”的实现。
1 在许多常见场景中,它似乎可以很好地产生不同的值。显然它不能防止哈希冲突,但是如果你的ID实际上是从1,2,3的序列生成的...那么这在异或的真实冲突中会做得更好。我确实看到了一个分析这种方法的网页以及哪些数字运作良好等等,但我不记得在哪里。