我在这里的许多问题都涉及到IEquatable的实现。 我发现正确实施是非常困难的,因为在天真的实现中存在很多隐藏的错误,而我发现的文章相当不完整。 我想find或写一个明确的参考,其中必须包括: 如何正确实现IEquatable 如何正确覆盖Equals 如何正确覆盖GetHashCode 如何正确实现ToString方法 如何正确实现运算符== 如何正确执行操作符! 这样一个完整的参考已经存在? PS:即使MSDN的参考似乎有缺陷给我
根据MSDN ,哈希函数必须具有以下属性: 如果两个对象相等,每个对象的GetHashCode方法必须返回相同的值。 但是,如果两个对象的比较不相等,则两个对象的GetHashCode方法不必返回不同的值。 对象的GetHashCode方法必须始终返回相同的哈希码,只要不会修改确定对象Equals方法的返回值的对象状态。 请注意,这仅适用于应用程序的当前执行,并且如果应用程序再次运行,则可以返回不同的散列码。 为了获得最佳性能,散列函数必须为所有input生成一个随机分布。 我不断发现自己在以下情况:我已经创build了一个类,实现了IEquatable<T>并重写IEquatable<T> object.Equals(object) 。 MSDN指出: 覆盖Equals的types也必须覆盖GetHashCode; 否则,Hashtable可能无法正常工作。 然后它通常会阻止我一点。 因为,你如何正确覆盖object.GetHashCode() ? 从来没有真正知道从哪里开始,这似乎是一个很大的陷阱。 在StackOverflow中,有很多与GetHashCode覆盖有关的问题,但是其中大部分似乎都是针对特定情况和特定问题。 所以,我想在这里得到一个很好的汇编。 一般build议和指导方针的概述。 该怎么做,不该做什么,常见的陷阱,从哪里开始等等。 我希望它特别针对C#,但是我认为它对于其他.NET语言也是如此(?)。 我想也许最好的办法是先用快速简短的答案为每个主题创build一个答案(如果可能的话,接近一行),然后可能会有更多的信息,并结束相关的问题,讨论,博客文章等。 ,如果有的话。 然后,我可以创build一个职位作为接受的答案(顶部),只是一个“目录”。 尽量保持简短。 不要只链接到其他问题和博客文章。 尝试把它们的本质,然后链接到源代码(尤其是源代码可能会消失。另外,请尝试编辑和改进答案,而不是创build很多非常相似的代码。 我不是一个很好的技术作家,但是我至less会尝试devise一些格式相似的答案,创build目录等等。我也会尝试在这里search一些相关的问题,这些,也许拉出我可以pipe理的精髓。 但是由于我对这个话题不太稳定,所以我会尽量远离:
我只是好奇,因为我猜它会影响性能。 它考虑完整的string吗? 如果是的话,长串会慢。 如果只考虑string的一部分,那么性能会很差(例如,如果只考虑string的开始,如果HashSet包含大部分相同的string,则性能会很差。
我已经读过关于何时以及如何重写GetHashCode 10个不同的问题,但仍然有一些我不太明白。 GetHashCode大部分实现都基于对象字段的哈希码,但是被引用的是, GetHashCode的值不应该在对象的生命周期中改变。 如果它基于的字段是可变的,它是如何工作的? 另外,如果我想要字典查找等基于参考平等而不是我重写的Equals ? 我主要覆盖Equals的unit testing我的序列化代码,我假设序列化和反序列化(在我的情况下XML)杀死引用相等,所以我想确保至less它是正确的值相等。 在这种情况下这是不好的做法覆盖Equals ? 基本上在大多数执行代码我想引用相等,我总是使用== ,我不重写。 我应该只是创build一个新的方法ValueEquals或东西,而不是重写Equals ? 我曾经假设框架总是使用==而不是Equals来比较事物,所以我认为覆盖Equals是安全的,因为在我看来,它的目的是为了如果你想有一个平等的第二个定义是不同的==运算符。 从阅读其他几个问题,但似乎并非如此。 编辑: 看来我的意图还不清楚,我的意思是99%的时候我想要老旧的参考平等,默认行为,没有什么意外。 对于非常罕见的情况,我希望具有值相等性,并且我希望通过使用.Equals而不是==来明确请求值相等。 当我这样做时,编译器build议我重写GetHashCode ,这就是这个问题的出现。 当应用于可变对象时,似乎存在与GetHashCode相矛盾的目标,那些目标是: 如果a.Equals(b)则a.GetHashCode()应该== b.GetHashCode() 。 a.GetHashCode()的值不应该在a的生命周期中改变。 当一个可变对象出现时,这些看起来自然是矛盾的,因为如果对象的状态发生变化,我们期望.Equals()的值改变,这意味着GetHashCode应该改变以匹配.Equals()中的改变,但是GetHashCode不应该更改。 为什么似乎有这个矛盾呢? 这些build议是不是适用于可变对象? 可能假设,但可能值得一提的是我指的是类而不是结构。 parsing度: 我将JaredPar标记为已接受,但主要针对评论交互。 总结一下,我从中学到的是,实现所有目标和避免在边缘情况下可能出现的奇怪行为的唯一方法是仅基于不可变字段覆盖Equals和GetHashCode ,或者实现IEquatable 。 这种似乎减less了重写Equals for引用types的用处,因为从我看到的大多数引用types通常没有不可变的字段,除非它们被存储在关系数据库中用它们的主键标识它们。
我想了解接口IEqualityComparer的GetHashCode方法的作用。 以下示例来自MSDN: using System; using System.Collections.Generic; class Example { static void Main() { try { BoxEqualityComparer boxEqC = new BoxEqualityComparer(); Dictionary<Box, String> boxes = new Dictionary<Box, string>(boxEqC); Box redBox = new Box(4, 3, 4); Box blueBox = new Box(4, 3, 4); boxes.Add(redBox, "red"); boxes.Add(blueBox, "blue"); Console.WriteLine(redBox.GetHashCode()); Console.WriteLine(blueBox.GetHashCode()); } catch (ArgumentException argEx) { Console.WriteLine(argEx.Message); } } […]
GetHashCode()的默认实现如何工作? 它是否有效和足够好地处理结构,类,数组等等? 我试图决定在什么情况下我应该收拾我自己,在什么情况下我可以安全地依靠默认实现来做好。 如果可能的话,我不想重新发明轮子。
引用Eric Lippert的GetHashCode指南和规则 : 规则: GetHashCode的使用者不能依赖于它随着时间的推移或跨越应用程序域的稳定性 假设你有一个Customer对象,有一堆如Name,Address等字段。 如果在两个不同的进程中使两个这样的对象具有完全相同的数据,则不必返回相同的哈希码。 如果星期二在一个进程中创build这样的对象,closures它,并在周三再次运行程序,哈希代码可以不同。 这已经让人们过去了。 System.String.GetHashCode的文档特别指出,两个相同的string可以在CLR的不同版本中具有不同的哈希码,事实上他们也可以。 不要在数据库中存储string散列,并期望它们永远是一样的,因为它们不会。 那么创build一个可以存储在数据库中的string的HashCode的正确方法是什么? (请告诉我,我不是第一个在我写的软件中留下这个bug的人!)
有没有办法获得一个实例的唯一标识符? 对于指向同一个实例的两个引用, GetHashCode()是相同的。 但是,两个不同的实例可以(非常容易地)获得相同的哈希码: Hashtable hashCodesSeen = new Hashtable(); LinkedList<object> l = new LinkedList<object>(); int n = 0; while (true) { object o = new object(); // Remember objects so that they don't get collected. // This does not make any difference though 🙁 l.AddFirst(o); int hashCode = o.GetHashCode(); n++; if (hashCodesSeen.ContainsKey(hashCode)) { // Same […]
在.NET中System.Object.GetHashCode方法被用在很多地方,在整个.NET基类库中。 特别是在快速查找collections中的物品或确定平等时。 是否有一个标准的algorithm/最佳做法如何实现我的自定义类的GetHashCode覆盖,所以我不降低性能?