C# 键存在,但给定KeyNotFound异常

C# 键存在,但给定KeyNotFound异常,c#,dictionary,C#,Dictionary,我创建了一个类,它使用自定义类作为键和值来创建字典,并通过xml序列化来存储它。然后单击“加载”反序列化xml文件并加载数据 问题在于以下代码。在反序列化并尝试加载字典后,我一直在这里收到KeyNotFound异常: foreach (Perk p in perksTier1[skill]) { string s = p.Name.ToString(); if (!lboxTier1.Items.Contains(s)) lboxTier1.Items.Add(s

我创建了一个类,它使用自定义类作为键和值来创建字典,并通过xml序列化来存储它。然后单击“加载”反序列化xml文件并加载数据

问题在于以下代码。在反序列化并尝试加载字典后,我一直在这里收到KeyNotFound异常:

foreach (Perk p in perksTier1[skill])
{
    string s = p.Name.ToString();
    if (!lboxTier1.Items.Contains(s))
        lboxTier1.Items.Add(s);
}
然而,当我一步一步地浏览代码并检查字典时,它看起来就像它应该做的一样,并且清楚地显示了技能键

这里是真正奇怪的部分: 使用ContainsKey返回null,但使用GetKeys会得到密钥


呜。请帮忙

您提到了
ContainsKey
,但您使用的是
Contains
。它们不一样。Contains正在检查目录中的值。返回true或false。如果您得到的是NULL,则说明您使用的方法不正确。

Huzzah!找到了。有关详细信息,请参阅本文:

要修复导入的字典,我必须重写技能类中的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;
    }

(感谢迈克和普雷斯顿为我指出了正确的方向)

您的钥匙是一个自定义对象。默认情况下,字典将使用对象引用比较来确定给定的键实例是否存在于字典的
Keys
集合中。由于它使用引用比较,引用并不相同,因为它们将指向不同的引用(即使它们可能“看起来”相同,因为它们具有相同的值)


你需要告诉字典它应该如何测试平等性。这通常是在用作键的对象中完成的,在本例中,您的
技能
对象通过提供自定义Equals方法或通过实现定义用于确定两个实例是否相等的“规则”的
EqualityComparer
对象来实现。

根据您的解释,您使用自定义类作为键

使用引用类型作为键时,需要确保使用对字典键所引用的同一对象的引用

例如,如果您有此类型

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));
然后使用您选择的序列化程序对其进行序列化

Serializer.Serialize(skill1,streem);
然后像这样反序列化它

Skill skill1 = new Skill(){SkillName = "C#"};
Skill skill2 = Serializer.Deserialize(stream);
和print
skill1==skill2
您会发现它将返回false,这是因为序列化程序在反序列化对象时所做的是创建新对象并使用第一个对象具有的相同值填充它

规则非常简单,引用相等基于指向同一对象,而不是指向具有相同属性值的两个不同对象


如果你没有提供足够的信息,我希望我能抓住要点

你确定它们是相等的字符串(如果键是字符串)吗?也许不同的外壳?在
perksTier1[skill]
中,您从哪里得到错误?可能在键值之前或之后有一些尾随空格,您在inspector中看不到这些空格?当从字节数组反序列化到对象中时,我经常遇到这个错误。试试skill.Trim()看看会发生什么?如果您使用的是作为键编写的其他类,那么您是如何实现GetHashCode和Equals的?必须实现这些方法,字典才能按预期运行。您可以向字典提供
iequalitycomparer
的实现,而不是在类本身上定义相等。此外,Ken…关于VS的漏洞是一个笑话。看到c#标签了吗?我知道IDE和语言之间的区别。
ListBox.Items
不是字典,他说的是
perksTier1
上的indexer。字典的定义是这样的:字典你应该阅读Mike评论中的链接,这个实现可能看起来像预期的那样工作,但它会产生误报。(你也应该避免不安全的演员阵容)很好的解释,谢谢。(我没有包括我的完整代码,因为它非常长,不包括单独的Perk、Skill和serialization类)
Skill skill2 = Serializer.Deserialize(stream);