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给我的键

自慰。请帮助。

Key存在,但给出KeyNotFound异常

您提到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,这是因为序列化器在反序列化对象时所做的是创建一个新对象,并用与第一个对象相同的值填充它。

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

希望我说到点子上了,因为你没有提供足够的信息