我可以依靠GetHashCode()的值来保持一致吗?

时间:2020-03-05 18:50:25  来源:igfitidea点击:

假设正在使用相同的字符串值,则GetHashCode()的返回值是否保证是一致的? (C#/ ASP.NET)

我今天将代码上传到服务器上,但令我惊讶的是我不得不重新索引一些数据,因为与台式机相比,我的服务器(win2008 64位)返回了不同的值。

解决方案

回答

如果我没记错的话,GetHashCode在给定相同值的情况下是一致的,但是不能保证在框架的不同版本之间保持一致。

从String.GetHashCode()上的MSDN文档中:

The behavior of GetHashCode is dependent on its implementation, which might change from one version of the common language runtime to another. A reason why this might happen is to improve the performance of GetHashCode.

回答

我想知道32位和64位操作系统之间是否存在差异,因为我确定我的服务器和家用计算机都运行相同版本的.NET。

我一直对使用GetHashCode()感到厌倦,对我来说,简单地扮演自己的哈希算法可能是个好主意。好吧,至少由于这个原因,我最终写了一个快速的重新索引.aspx页。

回答

我们是否正在将Win2008 x86作为桌面运行?因为Win2008包含版本2.0.50727.1434,它是Vista RTM中包含的2.0的更新版本。

回答

这不是乔纳斯回答得很好的直接答案,但是,如果我们担心哈希中的相等性测试,这可能会有所帮助

根据我们的测试,根据我们对哈希码的要求,在C#中,哈希码对于Equality操作不需要唯一。例如,请考虑以下内容:

我们需要重载equals运算符,因此我们的对象的GetHashCode函数变得易变且无状态,并直接从数据中获取自身,因此在应用程序的一个地方,我们需要确保可以查看对象如果它是从相同数据中获得的,则等于另一个对象,而不仅仅是它是相同的引用。我们唯一的数据标识符是Guid。

equals运算符很容易满足,因为我们只检查了记录的Guid(在检查了null之后)。

不幸的是,HashCode数据大小(为int)取决于操作系统,并且取决于我们的32位系统,哈希码将为32位。从数学上讲,当我们重写GetHashCode函数时,不可能从大于32位的guid生成唯一的哈希码(从相反的角度看,如何将32位整数转换为guid?)。

然后,我们进行了一些测试,将Guid作为字符串并返回了Guid的HashCode,该哈希码几乎总是在我们的测试中返回唯一标识符,但并非总是如此。

但是,我们注意到的是,当一个对象位于哈希收集对象(哈希表,字典等)中时,如果两个对象不是唯一的但它们的哈希码相同,则哈希码仅用作第一个选项查找,如果不-使用唯一的哈希码时,等于运算符始终用作确定等于的回退。

就像我说的那样,这可能与情况无关,但如果是的话,这是一个方便的提示。

更新

为了演示,我们有一个哈希表:

键:对象A(哈希码1),值对象A1

键:对象B(哈希码1),值对象B1

键:对象C(哈希码1),值对象C1

键:对象D(哈希码2),值对象D1

键:对象E(哈希码3),值对象E1

当我使用对象A的键调用对象的哈希表时,将在2个步骤后返回对象A1,即调用哈希码1,然后对键对象进行相等检查,因为哈希码1没有唯一的键

当我使用对象D的键调用对象的哈希表时,将在1步(哈希查找)之后返回对象D1

回答

What we did notice however, when an
  object is in a hashed collection
  object (a hashtable, a dictionary
  etc), when 2 objects are not unique
  but their hashcodes are, the hashcode
  is only used as a first option lookup,
  if there are non-unique hash codes
  being used, the equality operator is
  always used as a fall back to
  detirmine equality.

这是哈希查找工作的方式,对吗?每个存储桶均包含具有相同哈希码的项目列表。

因此,为了在这些条件下找到正确的项目,将进行使用值相等比较的线性搜索。

而且,如果散列实现实现了良好的分布,则不需要进行此搜索,即每个存储桶一项。

我的理解正确吗?

回答

实现取决于框架的版本,但也取决于体系结构。即使在框架的x86和x64版本中,string.GetHashCode()的实现也不同。

回答

我有一个类似的问题,我在数据库表中填充了依赖于String.GetHashCode的信息(不是最好的主意),当我将服务器升级到x64时,我注意到我从String.GetHashCode获得的值是与表格中已经存在的不一致。我的解决方案是使用自己的GetHashCode版本,该版本在x86框架上返回与String.GetHashCode相同的值。

这是代码,请不要忘记使用"允许不安全的代码"进行编译:

/// <summary>
    /// Similar to String.GetHashCode but returns the same as the x86 version of String.GetHashCode for x64 and x86 frameworks.
    /// </summary>
    /// <param name="s"></param>
    /// <returns></returns>
    public static unsafe int GetHashCode32(string s)
    {
        fixed (char* str = s.ToCharArray())
        {
            char* chPtr = str;
            int num = 0x15051505;
            int num2 = num;
            int* numPtr = (int*)chPtr;
            for (int i = s.Length; i > 0; i -= 4)
            {
                num = (((num << 5) + num) + (num >> 0x1b)) ^ numPtr[0];
                if (i <= 2)
                {
                    break;
                }
                num2 = (((num2 << 5) + num2) + (num2 >> 0x1b)) ^ numPtr[1];
                numPtr += 2;
            }
            return (num + (num2 * 0x5d588b65));
        }
    }

回答

我不得不说...我们不能依靠它。例如,如果我通过c#的md5哈希代码运行file1,然后将nd复制并将其粘贴到新目录中,则哈希码会变得不同,即使是同一文件也是如此。显然,它是相同的.net版本,所有内容都相同。唯一改变的是路径。