【发布时间】:2013-08-20 16:41:46
【问题描述】:
我有一个 SortedDictionary 声明如下:
SortedDictionary<MyObject,IMyInterface> dict = new SortedDictionary<MyObject,IMyInterface>();
当它填充了值时,如果我从字典中获取任何键,然后尝试立即引用它,我会得到一个KeyNotFoundException:
MyObject myObj = dict.Keys.First();
var value = dict[myObj]; // This line throws a KeyNotFoundException
当我使用调试器将鼠标悬停在字典上(出现错误后)时,我可以清楚地看到我试图引用的同一个键实际上包含在字典中。我使用MyObjects 的ReadOnlyCollection 填充字典。也许那里正在发生一些奇怪的事情?我尝试覆盖 == 运算符和 Equals 方法来获得我想要的显式比较,但没有这样的运气。这真的无关紧要,因为我实际上是直接从Dictionary 获取密钥,然后使用相同的密钥查询Dictionary。我无法弄清楚是什么原因造成的。有人见过这种行为吗?
编辑 1
在覆盖 Equals 时,我还重载了(如 MS 建议的那样)GetHashCode。下面是 MyObject 的实现,供任何感兴趣的人参考:
public class MyObject
{
public string UserName { get; set;}
public UInt64 UserID { get; set;}
public override bool Equals(object obj)
{
if (obj == null || GetType()!= obj.GetType())
{
return false;
}
// Return true if the fields match:
return this.Equals((MyObject)obj);
}
public bool Equals(MyObject other)
{
// Return true if the fields match
return this.UserID == other.UserID;
}
public override int GetHashCode()
{
return (int)this.UserID;
}
public static bool operator ==( MyObject a, MyObject b)
{
// If both are null, or both are same instance, return true.
if (System.Object.ReferenceEquals(a, b))
{
return true;
}
// If one is null, but not both, return false.
if (((object)a == null) || ((object)b == null))
{
return false;
}
// Return true if the fields match:
return a.UserID == b.UserID
}
public static bool operator !=( MyObject a, MyObject b)
{
return !(a == b);
}
}
我在调试中注意到的是,如果我为表达式添加一个快速监视(在抛出 KeyNotFoundException 之后):
dict.ElementAt(0).Key == value;
它返回真。这怎么可能?
编辑 2
所以问题最终是因为SortedDictionary(以及Dictionary)不是线程安全的。有一个后台线程正在对字典执行一些操作,这似乎触发了集合的使用(将项目添加到集合中会这样做)。同时,当字典遍历值以找到我的键时,集合正在更改,即使它在那里也找不到我的键。
对于所有要求提供此代码的人,我很抱歉,我目前正在调试我继承的应用程序,但我没有意识到这是在定时后台线程上进行的。因此,我以为我复制并粘贴了所有相关代码,但我没有意识到在操作集合的所有内容背后还有另一个线程在运行。
【问题讨论】:
-
您需要覆盖 Equals(和GetHashCode),尽管您可能还想重载它。请展示您的课程 - 或者更确切地说,展示问题的简短但完整的程序。
-
要明确:您首先观察到这一点,没有任何 Equals/==/GetHashCode 的覆盖/重载?因为 thos 的错误实现将是一个简单的答案。
-
@JonSkeet - 你说得对,我打错了。我确实覆盖
Equals(和GetHashCode)方法。我添加了相关代码。 -
@HenkHolterman 好问题!我在覆盖
Equals和GetHashCode方法之前就看到了问题,当我发现问题时就沿着这条路走。 -
@JoelB:但它们不是一个简短但完整的程序,是吗?我说的是一个完整的程序(最好是控制台应用程序),我可以复制、粘贴、编译、运行并查看您所看到的问题。
标签: c# dictionary readonly-collection