好的,在你们看到互联网上有数百个类似问题的帖子之前不要生气,我可以向你保证,我刚刚花了几个小时阅读了所有这些帖子,并没有找到我问题的答案。
背景:
基本上,我的一个大型应用程序一直遭受着这样一种情况:当对当前选定的项目进行编辑后,ListBox.SelectedItem
属性上的一些Binding
会停止工作或程序会崩溃。我最初在这里发布了问题,但没有得到答案。
我一直没有时间解决这个问题,直到这周我被给了几天的时间来解决它。现在说长话短说,我找出了问题的原因。这是因为我的数据类型类覆盖了Equals
方法,因此也覆盖了GetHashCode
方法。
对于那些不知道这个问题的人,我发现你只能使用不可变的字段/属性实现GetHashCode
方法。使用Harvey Kwok在Overriding GetHashCode()帖子中的一段摘录来解释这个问题:
问题在于Dictionary和HashSet集合使用GetHashCode将每个项放入桶中。如果哈希码基于某些可变字段进行计算,而对象被放置到HashSet或Dictionary后字段实际上发生了更改,则该对象将无法从HashSet或Dictionary中找到。
所以,实际上的问题是由于我在GetHashCode
方法中使用了可变的属性。当用户在UI中更改这些属性值时,对象的关联哈希码值会发生改变,然后项目就无法在它们的集合中找到。
问题:
那么,我的问题是在没有不可变字段的类中实现GetHashCode
方法的最佳方式是什么?抱歉,让我更具体一些,因为已经有人问过这个问题。
Overriding GetHashCode()帖子中的答案表明,在这些情况下,最好只需返回一个常量值......有些人建议返回值1
,而其他人则建议返回质数。就个人而言,我看不出这些建议之间有任何区别,因为我认为任何一个值都只会使用一个桶。
此外,Eric Lippert的博客文章《GetHashCode的指导方针和规则》中有一节标题为指导方针:哈希码的分布必须是“随机”的,强调了使用算法导致使用的桶数量不足的缺点。他警告说,算法会减少使用的桶的数量,并在桶变得非常大时导致性能问题。显然,返回一个常量属于这个范畴。
我想在我所有的数据类型类中添加一个额外的Guid
字段(仅限于C#,而不是数据库),专门用于并仅用于GetHashCode
方法。因此,经过这么长时间的介绍,我的实际问题是哪种实现更好?总结如下:
总结:
在没有不可变字段的类中重写 Object.GetHashCode() 方法时,是更好地从 GetHashCode 方法返回一个常量,还是创建一个额外的只用于 GetHashCode 方法的 readonly 字段?如果应该添加一个新字段,它应该是什么类型的,我是否应该将其包含在 Equals 方法中?虽然我乐意收到任何人的答案,但我真的希望从具有对此主题有深入了解的高级开发人员那里得到答案。
Guid
,并将其用于获取哈希码。我个人会尽量不为了在字典中使用而向类型添加Guid
。或者,您可以使用诸如标识映射之类的东西来基于分离的不可变 ID(再次可能是Guid
,因此实际上是相同的结果)为对象键入。或者再次替代方案是不要修改字典中的项。将它们键出,删除它们,修改它们,然后重新添加它们。 - Adam HouldsworthEquals
和GetHashCode
的覆写?在MSDN上的IEquatable<T>
接口页面上说它应该被实现在任何可能存储在通用集合中的对象上,然后在IEquatable<T>.Equals
方法页面上说如果你实现了Equals方法,你也应该覆盖基类的Object.Equals(Object)和GetHashCode方法,以保持其行为与IEquatable<T>一致。 - Sheridan