![]() |
1
28
显而易见的潜在答案是:因为这会消耗内存。 这里有一个成本/收益分析: 成本 :每个字符串4个字节(以及每次调用GetHashCode时的快速测试)。还要使string对象可变,这显然意味着您需要小心 实施-除非你 预先计算哈希代码,这是计算一次的开销 字符串,不管你是否把它散列过。 利益 :避免重新计算哈希 对于多次散列的字符串值 我建议,在很多情况下,有很多很多字符串对象,很少有对象被多次散列,这导致了净成本。在某些情况下,显然情况并非如此。 我不认为我能很好地判断哪一个更经常出现。。。我希望微软已经安装了各种真正的应用程序(我也希望Sun对Java也这么做 做 缓存哈希…) 是 |
![]() |
2
13
首先,不知道缓存这个结果是否真的会改善
如果您遵循StringComparer类的可能调用链,它最终将进入System.Globalization.CompareInfo类,该类最终在以下方法终止:
不知道该库(看起来是一个本机方法)是否使用了某种形式的基于底层.Net对象数据结构的内部缓存,而这种缓存是我们在.Net运行时中无法立即获得的。 但是,需要注意的重要一点是,一个字符串可以有 许多不同的 基于您选择如何解释字符的哈希代码。当然,这个实现是特定于文化的-这就是为什么它不适合这些比较器。 所以,当额外的内存存储 能够 作为一个因素,我实际上认为这是因为将散列代码与字符串实例一起存储会误导调用者,甚至误导.Net内部开发团队(!),认为字符串只有一个散列码,而事实上它完全取决于如何解释它-作为一系列字节(我们大多数人没有),或作为一系列可打印字符。
从性能的角度来看,如果我们也接受
编辑 蒂姆的回答中也提到了这一点。如果他是对的,而且我认为他是对的,那么不能保证字符串在构造之后实际上是不可变的,因此缓存结果是错误的。 附加编辑(!) Dan指出,字符串在netsphere中是不可变的,因此字符串应该可以基于此自由缓存自己的hashcode。这里的问题是.Net框架还提供了 更改假定不可变字符串的合法方法 这不涉及特权反思或其他任何事情。这是字符串的一个基本问题,它是指向无法控制的缓冲区的指针。不用担心,在C++世界里,C++中,如何引导和修改内存缓冲区是常见的地方。只是因为你 不应该 这样做并不意味着框架应该期望您不这样做。 .Net恰好提供了这个功能,因此,如果这是.Net团队针对Tim建议的那种二进制恶作剧而做出的设计决定,那么他们考虑到这一点是非常明智的。他们是否做到了,或者是出于侥幸,完全是另一回事了!:) |
![]() |
3
12
例如,如果你这么想做。。。
…不会的
|
![]() |
4
1
另一个可能的原因是,内部字符串(特别是那些由编译器作为共享只读数据添加的字符串)可以与任何其他字符串具有完全相同的格式。这些字符串被加载到只读内存的事实意味着这些数据页可以很容易地在进程间共享,但是也不可能让它们缓存哈希代码。
|
![]() |
5
1
是的,它会占用内存,但更重要的是,即使您不使用此功能,它也会占用内存。
也许优化hashcode会有好处
不管怎样,实现自己的目标应该很简单:
缺点是实习费用。在任何地方使用它都是一种过度杀伤力。典型的使用场景是
升级版本: 顺便说一句,我有 packaged it check it out . |
![]() |
6
0
现在考虑一下
如果是
当字典进行键查找时,它计算要搜索的键的修改的(即正的)HashCode,获取HashCode映射到的bucket,然后查看该bucket中的条目列表。要检查条目是否匹配,它首先检查修改后的哈希码是否匹配(如果键相等,哈希码也必须相等),如果相等,则检查两个键是否相等。在字符串的情况下,这个算法实现了两件事;首先,它通过使用一个简单的整数比较来避免许多字符串比较,首先看是否值得进行字符串比较,其次,它缓存字典中每个键的hashcode。 当键/值对被添加到字典中时,字典中每个键的HashCode只计算一次 . (如果您想知道为什么Dictionary会从HashCode中删除符号位,那是因为Dictionary在HashCode字段中将-1用作当前为空的条目槽的标记标志值。) |