【问题标题】:string.GetHashCode() returns different values in debug vs release, how do I avoid this?string.GetHashCode() 在调试与发布中返回不同的值,我该如何避免这种情况?
【发布时间】:2011-11-23 22:51:10
【问题描述】:

令我惊讶的是,以下方法在调试和发布中产生了不同的结果:

int result = "test".GetHashCode();

有什么办法可以避免吗?

我需要一种可靠的方法来散列字符串,并且我需要该值在调试和发布模式下保持一致。如果可能,我想避免编写自己的哈希函数。

为什么会这样?

仅供参考,反射器给了我:

[ReliabilityContract(Consistency.WillNotCorruptState, Cer.MayFail), SecuritySafeCritical]
public override unsafe int GetHashCode()
{
    fixed (char* str = ((char*) this))
    {
        char* chPtr = str;
        int num = 0x15051505;
        int num2 = num;
        int* numPtr = (int*) chPtr;
        for (int i = this.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));
    }
}

【问题讨论】:

  • 如果你需要哈希码保持一致,你就用错了。如果我没记错的话,他们明确强制它在调试模式下不一致,这样微软内部就没有人依赖它。
  • 欲了解更多信息,请参阅:Eric Lippert's post on guidelines for GetHashCode
  • GetHashCode 在 .NET 32 位和 .NET 64 位上也返回不同的值。

标签: c# string debugging release gethashcode


【解决方案1】:

GetHashCode()不是你应该用它来散列一个字符串,几乎 100% 的时间。在不知道自己在做什么的情况下,我建议您使用实际的哈希算法,例如 SHA-1:

using(System.Security.Cryptography.SHA1Managed hp = new System.Security.Cryptography.SHA1Managed()) {
    // Use hp.ComputeHash(System.Text.Encoding.ASCII (or Unicode, UTF8, UTF16, or UTF32 or something...).GetBytes(theString) to compute the hash code.
}

更新:对于更快一点的东西,还有SHA1Cng,它比SHA1Managed快得多。

【讨论】:

  • 我已经有很多代码需要一个 int,它对性能也很关键,这就是我想使用 internal 方法的原因。你能创建一个返回int的快速哈希吗?我将它打包成一个扩展方法,例如GetHashCodeStable()
  • @Joe:这对性能至关重要?你的具体情况是什么?如果它只是需要有点快,散列函数仍然相当快。也许尝试MD5。 (无论如何,结果可以很容易地转换成int,只取最后4个字节什么的。)
  • 速度有点快是可以的,我一直认为 SHA1、MD5 等相对于像反编译的 GetHashCode 这样的简单循环来说比较慢
  • @Joe:它本质上是一个循环 :) 但是如果你测试它并且性能不可接受,你也可以创建自己的哈希到 int 的方法;网上有几种算法。我刚刚找到的一个是最后一个帖子:linuxquestions.org/questions/programming-9/…
  • 我最终使用了一个修改版本的发布 GetHashCode 植入并将其命名为 GetHashcodeStabe() 我给你正确答案是因为我认为你的解决方案确实是正确的方法,我只使用了由于性能要求而采用不同的方法,尽管如上所述,这种方法不是很慢
【解决方案2】:

这是一种比 SHA 快得多的更好方法,您可以用它替换修改后的 GetHasCode:C# fast hash murmur2

有几种不同级别的“非托管”代码实现,所以如果你需要完全托管,它就在那里,如果你可以使用 unsafe,它也在那里。

【讨论】:

    【解决方案3】:
        /// <summary>
        /// Default implementation of string.GetHashCode is not consistent on different platforms (x32/x64 which is our case) and frameworks. 
        /// FNV-1a - (Fowler/Noll/Vo) is a fast, consistent, non-cryptographic hash algorithm with good dispersion. (see http://isthe.com/chongo/tech/comp/fnv/#FNV-1a)
        /// </summary>
        private static int GetFNV1aHashCode(string str)
        {
            if (str == null)
                return 0;
            var length = str.Length;
            // original FNV-1a has 32 bit offset_basis = 2166136261 but length gives a bit better dispersion (2%) for our case where all the strings are equal length, for example: "3EC0FFFF01ECD9C4001B01E2A707"
            int hash = length;
            for (int i = 0; i != length; ++i)
                hash = (hash ^ str[i]) * 16777619;
            return hash;
        }
    

    我猜这个实现比here 发布的不安全实现要慢。但它更简单、更安全。在不需要超高速的情况下效果很好。

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多