【发布时间】:2019-07-14 09:32:59
【问题描述】:
我的问题基本上与Dictionary.ContainsKey return False, but a want True和"the given key was not present in the dictionary" error when using a self-defined class as key相反:
我想使用一个中等大小的类作为字典的键,字典必须通过引用来比较键,而不是值相等。问题是,该类已经实现了Equals()(它正在执行值相等——这不是我想要的)。
这是一个用于重现的小型测试类:
class CTest
{
public int m_iValue;
public CTest (int i_iValue)
{
m_iValue = i_iValue;
}
public override bool Equals (object i_value)
{
if (ReferenceEquals (null, i_value))
return false;
if (ReferenceEquals (this, i_value))
return true;
if (i_value.GetType () != GetType ())
return false;
return m_iValue == ((CTest)i_value).m_iValue;
}
}
我还没有实现GetHashCode()(实际上我已经实现了,但到目前为止它只返回base.GetHashCode())。
现在我创建了一个带有字典的测试程序,该字典使用此类的实例作为键。我可以毫无问题地将多个相同的实例添加到字典中,但这仅适用于 GetHashCode() 返回不同的值:
private static void Main ()
{
var oTest1 = new CTest (1);
var oTest2 = new CTest (1);
bool bEquals = Equals (oTest1, oTest2); // true
var dict = new Dictionary<CTest, int> ();
dict.Add (oTest1, 1);
dict.Add (oTest2, 2); // works
var iValue1 = dict[oTest1]; // correctly returns 1
var iValue2 = dict[oTest2]; // correctly returns 2
int iH1 = oTest1.GetHashCode (); // values different on each execution
int iH2 = oTest2.GetHashCode (); // values different on each execution, but never equals iH1
}
而且哈希值每次都不同,可能是因为object.GetHashCode() 中的计算使用了一些随机化或来自参考句柄的一些数字(每个对象都不同)。
但是,Why is it important to override GetHashCode when Equals method is overridden? 上的 this answer 说 GetHashCode() 必须为相等的对象返回相同的值,所以我添加了
public override int GetHashCode ()
{
return m_iValue;
}
在那之后,我不能再向字典中添加多个相等的对象了。
现在,有两个结论:
- 如果我再次删除我自己的
GetHashCode(),哈希值将再次不同,并且可以使用字典。但是可能会出现意外给两个相等的对象给出相同的哈希码的情况,这会在运行时导致异常,其原因肯定永远找不到。由于那个(很小,但不是零)风险,我不能使用字典。 - 如果我按照我应该做的那样正确实现
GetHashCode(),我无论如何都不能使用字典。
还有哪些可能仍然使用字典?
【问题讨论】:
-
您可以通过在对象之间使用分隔符来获得重复的哈希值。例如,如果 x = hash(a)、y = hash(b) 和 xy = hash(c)。所以你有 xy = hash(a) + hash(b) = hash(c)。所以为了防止重复使用像'^'这样的分隔符所以哈希x^y = hash(a) + hash(b) while xy = hash(c)。
标签: c# class dictionary key