Guid和GetHashCode的唯一性

鉴于以下关键:

int key = Guid.NewGuid().GetHashCode(); 

这个钥匙作为Guid的独特性是独一无二的吗?

鸽笼原则说没有。 GUID有16个字节的信息 – 128位。 int有32位信息。 (编辑:为了澄清由于注释,.NET GUID将允许这些128位任意设置,据我所知;随机生成的GUID遵循更严格的模式,因此没有2 128个不同的值,这将是随机的但仍然超过2 32。

有2 128个可能的GUID和2 32个可能的哈希码 – 因此您不可能为每个GUID使用不同的哈希码。

不仅如此 – GetHashCode()绝不代表唯一性。 如果它可以 ,那么这很好 – 但它没有必要,即使有足够的int值可用。

int.GetHashCode()返回(比方说)除以2的值是完全有效的 ……所以-1,0和1都将得到哈希码0; 3和4将得到2的哈希码等。它不会好(并且它会比返回值慢) – 但它将是一个有效的实现。 它将满足GetHashCode所有约束 – 即如果你在两个相等的值上调用它,它将返回相同的哈希码。

事实上,为所有值返回一个常量是一个有效的实现 – 尽管它是一个相当无用的实现,因为它将哈希表的正常快速查找呈现为O(N)操作。

GetHashCode()返回一个整数 – 它不能像Guid一样唯一,所以不 – 可能存在冲突,并且不保证唯一性。

哈希码的重点是它应该在哈希范围内均匀分布,这样冲突通常很少,但你总是有碰撞的机会,并且必须适应这种情况。

就在今天,我已经注意到Guid.GetHashCode()另一个问题:在Microsoft .NET实现中,并非Guid每个“字节”都经过哈希处理: Guid的6个字节没有经过哈希处理,因此任何更改都是其中一个不会改变哈希码。

我们可以在参考源中看到它:

 return _a ^ (((int)_b << 16) | (int)(ushort)_c) ^ (((int)_f << 24) | _k); 

所以_d_e_g_h_i_j字节不进行哈希处理。 这对“顺序” Guid有重要影响,如:

 c482fbe1-9f16-4ae9-a05c-383478ec9d13 c482fbe1-9f16-4ae9-a05c-383478ec9d14 c482fbe1-9f16-4ae9-a05c-383478ec9d15 ... c482fbe1-9f16-4ae9-a05c-383478ec9dff c482fbe1-9f16-4ae9-a05c-383478ec9e00 c482fbe1-9f16-4ae9-a05c-383478ec9e01 

Guid一样,生成的不同哈希值的数量非常少(256个不同的值),因为3478ec9d / 3478ec9e不会被散列。

Guid是一个128位的数字。 int是32位数字,因此它不能像Guid那样“独特”。

此外,GetHashCode返回…一个哈希码,它并不意味着任何方式都是唯一的。 有关GetHashCode()存在的原因,请参阅此处的其他讨论。

我正好知道xanatos在另一个答案中描述的问题。 我有一个类,其中两个Guid值用于区分不同的对象,我发现我得到了可怕数量的碰撞(我的Guids不是随机生成的)。 这是我用来解决问题的代码。 Guid1Guid2是区分对象的Guid类型的属性。 该代码遵循Jon Skeet在此描述的方法 。

  public override int GetHashCode() { int hash = 173; foreach (Byte b in Guid1.ToByteArray().Concat(Guid2.ToByteArray())) { hash = hash * 983 + b; } return hash; }