密钥存在,但给出了KeyNotFound异常

时间:2015-05-28 02:47:30

标签: 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);
}

但是,当我单步执行代码并检查字典时,它看起来应该是正确的,并且显示技能键。

这是非常奇怪的部分: 使用ContainsKey返回null,但使用GetKeys GIVES ME THE KEY

WUT。请帮忙。

4 个答案:

答案 0 :(得分:1)

您提及ContainsKey,但您使用的是Contains。他们不一样。包含正在检查dictonary中的值。 ContainsKey Method返回true或false。如果您获得NULL,则使用的方法不正确。

答案 1 :(得分:0)

好哇!找到了。有关详细信息,请参阅此帖子:GetHashCode and Equals implementation in 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指出我正确的方向)

答案 2 :(得分:0)

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

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

答案 3 :(得分:0)

根据您的说明,您使用自定义类作为密钥。

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

例如,如果您有此类型

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));

您会注意到控制台行现在正在打印。这是因为查找引用指向字典所具有的相同对象。

这与您的问题有什么关系?它的序列化和反序列化。如果你像这样创建一个Skill类型的对象

Skill skill1 = new Skill(){SkillName = "C#"};

然后使用您选择的序列化程序对其进行序列化

Serializer.Serialize(skill1,streem);

然后你像这样反序列化

Skill skill2 = Serializer.Deserialize(stream);

并打印skill1 == skill2你会发现它会返回false,这是因为序列化程序在反序列化对象时所做的是它创建了新对象并使用与第一个对象相同的值填充它

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

希望我没有提供足够的信息,我已经到了现场