.net - 为什么 System.String 对象不缓存其哈希码?

标签 .net string immutability hashcode gethashcode

string.GetHashCode 的源代码一览使用Reflector显示以下内容(对于 mscorlib.dll 版本 4.0):

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));
    }
}

现在,我意识到the implementation of GetHashCode is not specified and is implementation-dependent ,所以问题“GetHashCode是以X还是Y的形式实现的?”并不真正负责。我只是对一些事情感到好奇:

  1. 如果 Reflector 已正确反汇编 DLL,并且这GetHashCode 的实现(在我的环境中),我对这段代码的解释是否正确,表明 string基于此特定实现的对象不会缓存其哈希码?
  2. 假设答案是肯定的,为什么会这样?在我看来,内存成本是最小的(多一个 32 位整数,与字符串本身的大小相比,简直就是小菜一碟),而节省的空间却是巨大的,特别是在使用字符串等情况下作为基于哈希表的集合中的键,例如 Dictionary<string, [...]> 。自从 string类是不可变的,它不像 GetHashCode 返回的值甚至会改变。

我可能会错过什么?

<小时/>

更新:回应 Andras Zoltan 的结束语:

There's also the point made in Tim's answer(+1 there). If he's right, and I think he is, then there's no guarantee that a string is actually immutable after construction, therefore to cache the result would be wrong.

哇,就在那里!这是一个有趣的观点(和 yes it's very true ),但我真的怀疑在实现 GetHashCode 时考虑到了这一点。 。 “因此缓存结果是错误的”这一说法对我来说意味着框架对字符串的态度是“嗯,它们应该是不可变的,但实际上,如果开发人员想要偷偷摸摸,他们就会这样做”它们是可变的,所以我们会这样对待它们。” 这绝对不是框架查看字符串的方式。它在很多方面完全依赖于它们的不变性(字符串文字的驻留、将所有零长度字符串分配给 string.Empty 等),基本上,如果你改变一个字符串,你正在编写的代码的行为完全是未定义且不可预测。

我想我的观点是,这个实现的作者会担心,“如果这个字符串实例在调用之间被修改怎么办,即使公开暴露的类是不可变的?”就像一个计划进行休闲户外烧烤的人会自言自语:“如果有人带着原子弹参加聚会怎么办?”听着,如果有人带来原子弹,派对就结束了。

最佳答案

明显的潜在答案:因为这会消耗内存。

这里有一个成本/效益分析:

成本:每个字符串 4 个字节(以及每次调用 GetHashCode 的快速测试)。还要使字符串对象可变,这显然意味着您需要小心 实现 - 除非您总是预先计算哈希码,这是为每个字符串计算一次的成本,无论您是否曾经对它进行哈希处理。

好处:避免为多次散列的字符串值重新计算散列

我建议,在很多情况下,有很多很多字符串对象,其中很少有被多次哈希的 - 导致净成本。对于某些情况,显然情况并非如此。

我认为我无法判断哪个出现的频率更高......我希望微软已经对各种真实的应用程序进行了检测。 (我也希望 Sun 对 Java 做同样的事情,它确实缓存哈希......)

编辑:我刚刚和 Eric Lippert 谈过这个问题(NDC 很棒:),基本上它是关于额外的内存消耗与有限的好处。

关于.net - 为什么 System.String 对象不缓存其哈希码?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/3053726/

相关文章:

c# - 在 C# 中动态创建的用户控件

c# - 正则表达式:使用通配符根据用户输入检查 IP 地址

string - autohotkey 将文本表达式分配给变量

string - 将日期变量拆分为组件

objective-c - 在 Objective-C 中隐藏不可变接口(interface)背后的私有(private)可变属性

c# - 带有可选参数的原始 SQL 插入语句

c# - IEnumerator IEnumerable vb 到 C#

java - parseFloat() 与 parseDouble()

java strings inmutable 但代码没有显示

c++ - 可以使用放置 "new"来更改 "const"数据吗?