我一直认为,鉴于 .Net 字符串是不可变的,String.GetHashCode()
不必每次调用时都计算哈希值——如果字符不会改变,那么对于给定的 System.String 实例,哈希值是恒定的,我天真地想法; String.GetHashCode()
可能有 O(1) 复杂度。
逆向工程打破了这个假设。
当然,哈希码并不意味着是恒定的等等,但是什么可以阻止 String 实现具有已经从构建时间计算的哈希码?
好问题!
基本上,这是速度/内存的权衡。缓存字符串哈希码的好处可以说被每个需要分配另外 32 位内存的单个字符串对象的开销所抵消。当您考虑程序中可能存在的大量字符串与您关心的哈希码的数量(可能是因为您将它们用作键)时,这是有道理的。
后一个数字在某些程序中可能很大,但也可能很小。在很多情况下,它甚至可能为零。
如果在某些情况下性能是您非常关心的问题,您可能会考虑编写自己的包装器来缓存其哈希码:
public class StringKey
{
string value;
int hashCode;
public StringKey(string value)
{
this.value = value;
this.hashCode = value.GetHashCode();
}
public override int GetHashCode()
{
return this.hashCode;
}
public override string ToString()
{
return this.value;
}
// Plus all the other stuff you'd want to include here,
// e.g., Equals, CompareTo, etc.
}
当然,要从中获得任何好处,您仍然需要非常小心地StringKey
在整个程序中到处重用这些对象。在绝大多数情况下,这不值得付出努力。如果您碰巧是个例外情况,我仅将这个想法作为考虑的事项。
仅当您假设(几乎)每次创建字符串时都使用哈希码时,这才有意义。如果你不使用哈希码,你仍然会付出计算的代价。我同意你的实习字符串,这实际上可能是值得的,只要它可以作为实习的一部分来完成。
我认为问题是在哪里存储哈希码。对字符串存储进行了如此多的优化,因为添加更多存储需求将过于复杂。