Guid& GetHashCode唯一性

时间:2011-09-06 21:52:37

标签: c# .net

给出以下密钥:

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

此密钥是否与Guid的唯一性一致?

5 个答案:

答案 0 :(得分:43)

pigeonhole principle说不。 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)操作

答案 1 :(得分:12)

GetHashCode()返回一个整数 - 它不能像Guid那样唯一,所以不 - 可能会发生冲突,并且无法保证唯一性。

散列码的要点是它应该在散列范围内均匀分布,这样碰撞通常很少见,但你总是有碰撞的机会,并且必须适应这种情况。 / p>

答案 2 :(得分:12)

就在今天,我已经注意到Guid.GetHashCode()的另一个问题:在Microsoft .NET实现中,而不是每个"字节"对Guid进行了散列:Guid中有6个字节没有被散列,因此对其中一个字节的任何更改都不会更改散列码。

我们可以在reference source

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

因此_d_e_g_h_i_j字节不会被散列。这对&#34;顺序&#34;有重要影响。 Guid s,如:

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不会被哈希。

答案 3 :(得分:4)

我在另一个答案中确切地the problem xanatos describes了。我有一个类,其中两个Guid值用于区分不同的对象,我发现我得到了可怕数量的碰撞(我的Guids不是随机生成的)。这是我用来解决问题的代码。 Guid1Guid2是区分对象的Guid类型的属性。代码遵循the approach described by Jon Skeet here

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

答案 4 :(得分:3)

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

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