Key存在,但给出KeyNotFound异常
本文关键字:KeyNotFound 异常 存在 Key | 更新日期: 2023-09-27 17:50:54
我创建了一个类,它使用自定义类作为键和值创建一个字典,并通过xml序列化存储它。然后点击"加载"反序列化xml文件并加载数据。
问题出在下面的代码。在反序列化并尝试加载字典后,我一直在这里获得KeyNotFound异常:
foreach (Perk p in perksTier1[skill])
{
string s = p.Name.ToString();
if (!lboxTier1.Items.Contains(s))
lboxTier1.Items.Add(s);
}
然而,当我遍历代码并检查字典时,它看起来就像它应该的那样,Skill键清楚地出现了。
这里是真正奇怪的部分:使用ContainsKey返回null,但使用GetKeys给我的键
自慰。请帮助。
您提到ContainsKey
,但您使用的是Contains
。它们不一样。Contains检查字典中的值。ContainsKey方法返回真或假。如果你得到NULL,你正在使用错误的方法。
好棒!找到了。GetHashCode和Equals在Dictionary c#中的实现
要修复导入的字典,我必须重写Skill类中的Equals和GetHashCode()方法:
public override bool Equals(object obj)
{
Skill newskill;
newskill = (Skill)obj;
return (obj.GetHashCode() == newskill.GetHashCode());
}
public override int GetHashCode()
{
int temp = name.GetHashCode();
return temp;
}
(感谢Mike和Preston为我指明了正确的方向)
键是一个自定义对象。默认情况下,字典将使用对象引用比较来确定给定的键实例是否存在于字典的Keys
集合中。由于它使用了引用比较,所以引用是不一样的,因为它们将指向不同的引用(即使它们可能"看起来"相同,因为它们具有相同的值)。
你需要告诉字典它应该如何测试相等。这通常在被用作键的对象中完成,在本例中是您的Skill
对象,通过提供自定义Equals方法或通过实现EqualityComparer<Skill>
对象来定义用于确定两个实例是否相等的"规则"。
根据您的解释,您正在使用自定义类作为密钥。
当使用引用类型作为键时,您需要确保使用对字典键所引用的对象的引用。
例如,如果你有这个类型
public class Skill
{
public string SkillName
{
get;
set;
}
}
那么你可以这样使用
Dictionary<Skill, object> dic = new Dictionary<Skill, object>();
for (int i = 0; i < 5; i++)
{
dic.Add(new Skill() { SkillName = i.ToString() }, new object());
}
Skill lookup = new Skill() { SkillName = "0"};
Console.WriteLine(dic.ContainsKey(lookup));
这将返回false,因为查找引用指向的对象与在循环中创建的对象不同,请注意SkillName具有相同的值(在本例中为"0")。
如果您将代码更改为以下
Dictionary<Skill, object> dic = new Dictionary<Skill, object>();
for (int i = 0; i < 5; i++)
{
dic.Add(new Skill() { SkillName = i.ToString() }, new object());
}
Skill lookup = dic.Keys.FirstOrDefault(sk => sk.SkillName == "0");
Console.WriteLine(dic.ContainsKey(lookup));
您将注意到控制台行现在打印为true。这是因为查找引用指向的对象与字典中的对象相同。
这和你的问题有什么关系?是序列化和反序列化。如果你像这样创建一个Skill类型的对象
Skill skill1 = new Skill(){SkillName = "C#"};
然后使用您选择的序列化器序列化它
Serializer.Serialize(skill1,streem);
然后像这样反序列化
Skill skill2 = Serializer.Deserialize(stream);
然后打印skill1 == skill2
,你会发现它将返回false,这是因为序列化器在反序列化对象时所做的是创建一个新对象,并用与第一个对象相同的值填充它。
规则非常简单,引用相等是基于指向同一个对象,而不是两个具有相同属性值的不同对象。
希望我说到点子上了,因为你没有提供足够的信息