public class TestHashRace
{
private int cachedHash = 0;
private readonly object value;
public object Value
{
get { return value; }
}
public TestHashRace(object value)
{
this.value = value;
}
public override int GetHashCode()
{
if (cachedHash == 0) {
cachedHash = value.GetHashCode();
}
return cachedHash;
}
//Equals isn't part of the question, but since comments request it, here we go:
public override bool Equals(object obj)
{
if (ReferenceEquals(null, obj)) return false;
if (ReferenceEquals(this, obj)) return true;
if (obj.GetType() != GetType()) return false;
return Equals((TestHashRace) obj);
}
protected bool Equals(TestHashRace other)
{
return Equals(value, other.value);
}
}
这是简单的测试类。
我们保证
GetHashCode
将始终返回相同的值?如果是的话,有人可以指出一些可以为我们提供这种保证的引用资料吗?
如果它为我们的值计算哈希码不止一次,我们并不担心,我们只想确保返回的值始终相同。
我们的类必须是不可变的,而
cachedHash
字段是可变的。出于性能原因,字段不能是 volatile (我们在这里质疑的这个问题和优化的整个想法)。值(value)是不可变的。而且它必须是线程安全的。当某些特定值的哈希码为 0 时,我们可以接受潜在的哈希码重新计算。我们不想使用可空类型或出于内存原因添加额外的字段(如果我们只存储 1 个 int 则使用更少的内存),因此它必须是一个 int 字段来处理哈希码问题。
最佳答案
Are we guaranteed that GetHashCode will always return the same value?
不。该保证仅适用于不可变
value
正确实现的对象 GetHashCode
方法。当可变对象的内容发生变异时,可变对象可能会更改其哈希码(这就是为什么不应该将可变对象用作哈希键的原因)。即使
TestHashRace
也是如此本身是不可变的,因为你可以这样做:var evil = new StringBuilder("hello");
var thr = new TestHashRace(evil);
RunConcurrentCode(thr);
evil.Append(", world!");
如果
RunConcurrentCode
中有多个线程开始调用 thr
的 GetHashCode
同时,然后在Append
的不同侧完成,从 value.GetHashCode
返回的数字可能不同。[Edit:] Value is immutable
那么保证书唯一需要的就是
value
的 GetHashCode
正确实现,即不使用随机内容等。注:由于零是哈希码的合法值,您的代码可能会重复调用
value
的 GetHashCode
当实际代码为零时。解决此问题的一种方法是使用可为空的 cachedHash
:int? cachedHash;
...
public override int GetHashCode() {
return cachedHash ?? (cachedHash = value.GetHashCode());
}
关于.net - 我们能保证通过数据竞争缓存哈希码能正常工作吗?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/40792730/