KeyNotFoundException in C# Dictionary after changing property value based on what, the GetHashCode is calculated. Why?
见下面的代码。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 | static void Main(string[] args) { // Create Dictionary var dict = new Dictionary<TestClass, ValueClass>(); // Add data to dictionary CreateSomeData(dict); // Create a List var list = new List<TestClass>(); foreach(var kv in dict) { // Swap property values for each Key // For example Key with property value 1 will become 6 // and 6 will become 1 kv.Key.MyProperty = 6 - kv.Key.MyProperty + 1; // Add the Key to the List list.Add(kv.Key); } // Try to print dictionary and received KeyNotFoundException. foreach (var k in list) { Console.WriteLine($"{dict[k].MyProperty} - {k.MyProperty}"); } } static void CreateSomeData(Dictionary<TestClass, ValueClass> dictionary) { dictionary.Add(new TestClass {MyProperty = 1}, new ValueClass {MyProperty = 1}); dictionary.Add(new TestClass {MyProperty = 2}, new ValueClass {MyProperty = 2}); dictionary.Add(new TestClass {MyProperty = 3}, new ValueClass {MyProperty = 3}); dictionary.Add(new TestClass {MyProperty = 4}, new ValueClass {MyProperty = 4}); dictionary.Add(new TestClass {MyProperty = 5}, new ValueClass {MyProperty = 5}); dictionary.Add(new TestClass {MyProperty = 6}, new ValueClass {MyProperty = 6}); } |
键和值班:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 | namespace HashDictionaryTest { public class TestClass { public int MyProperty { get; set; } public override int GetHashCode() { return MyProperty; } } } namespace HashDictionaryTest { public class ValueClass { public int MyProperty { get; set; } public override int GetHashCode() { return MyProperty; } } } |
我在Ubuntu下使用DotNet核心2。我做了这个测试不只是好奇。然而,我的惊喜,我keynotfoundexception。
我收到了预期的值。然而,在一收到的上述异常。
我想知道的是,为什么我们有这样的错误呢?什么是最好的实践中生成的hash码,这样我们可以避免这样的问题吗?
What I want to know is, why we got this error?
号
有关于gethashcode的指南,也有规则。如果你违反了这些准则,你会得到糟糕的表现。如果你违反了规则,事情就会破裂。
你违反了规则。GetHashCode的规则之一是当对象在字典中时,其哈希代码不得更改。另一个规则是相等的对象必须具有相等的哈希代码。
你违反了规则,所以一切都被打破了。那是你的错,不要违反规则。
What is the best practice in generating the HashCode so that we can avoid such issues?
号
有关规则和指南的列表,请参阅:
Guidelines and rules for GetHashCode
这是代码的预期行为。那么您的代码有什么问题?
看看你的钥匙课。您将覆盖您的
1 2 3 4 5 6 7 8 | public class TestClass { public int MyProperty { get; set; } public override int GetHashCode() { return MyProperty; } } |
字典实现中的查找使用插入对象的
在这里查找
1 | Console.WriteLine($"{dict[k].MyProperty} - {k.MyProperty}"); |
号
另一件非常重要的事情是要记住,当您覆盖
keynotFoundException…为什么?
蒸馏的核心原因是
- 覆盖
TestClass 中的Equals 。 - 迭代期间从不修改字典
- 关键对象/值正在修改
- …GetHashCode不应在对象的生命周期中更改。在计算
GetHashCode() 时,不要使用可能发生变化的值。- 不完全是。问题是在相等性不变的情况下更改哈希代码。
- msdn说:对象的getHashCode()方法必须始终返回相同的哈希代码,只要不修改确定对象的System.Object.Equals方法返回值的对象状态。
埃多克斯1〔19〕
我说
"EDOCX1"(12)和"EDOCX1"(13)类必须一致。当覆盖其中一个而不是两者时,则它们不一致。我们都知道"如果你覆盖
迭代字典
不要在迭代过程中添加或删除元素、修改键或修改值(有时)。
- 正在编辑字典值…在一个循环中——它碰到了一些技术原因,在迭代期间无法安全地修改字典条目。
- msdn字典文档
- 可以在迭代期间更改值-字典"value",而不是键的值
- 好吧,不是所有的情况
方法
- msdn获取哈希代码
- 不要将哈希代码用作从键控集合中检索对象的键。
- 不要测试哈希代码是否相等以确定两个对象是否相等
操作代码可能不会从字面上做到这一点,但实际上肯定是因为没有等号重写。
这是C demi God Eric Lipper的一个简单哈希算法