4

我需要使用我编写的类作为键的类型Dictionary

在 MSDN 上阅读了有关默认构造函数的文档Dictionary

Dictionary<TKey, TValue>需要一个相等实现来确定键是否相等。此构造函数使用默认的泛型相等比较器EqualityComparer<T>.Default. 如果 type TKey实现了System.IEquatable<T>泛型接口,则默认相等比较器使用该实现。或者,您可以IEqualityComparer<T>使用接受比较器参数的构造函数来指定通用接口的实现。

这使我认为我唯一要做的就是让我的课程用于关键实现System.IEquatable<T>

但是我很惊讶System.IEquatable<T>没有HashCode()方法。

那么以这种方式创建的字典会使用哈希码吗?如果是,它来自哪里?否则,我的字典是否会有恒定成本访问操作(我认为没有哈希码是无法实现的)

4

4 回答 4

4

但是我很惊讶 System.IEquatable 没有 HashCode() 方法。

System.IEquatable<T>拥有一个 HashCode 方法是多余的,因为System.Object(您的实现类将隐式继承)已经提供了GetHashCode方法

于 2012-11-14T19:18:33.137 回答
1

是的,字典将使用哈希码。字典实际上是封面下的哈希图。

它将使用的哈希码实现是GetHashCode您的密钥中实现的那个。如果您自己没有定义实现,则哈希码将基于引用类型的引用,以及值类型(结构)的各个字段。当使用您自己的类作为字典中的键时,建议实现GetHashCode.

当您实现时IEquatable<T>,您必须覆盖EqualsGetHashCodeon 对象以匹配您的IEquatable<T>. 它不在接口中的原因是它GetHashCode已经在 上定义object,所有类都派生自它,因此将它放在接口中不会有任何区别。

如果您未能实现GetHashCode它以匹配您的IEquatable<T>实现,您可能会遇到一个问题,即您将一个键放入字典中,但由于哈希码不匹配而无法再次检索它:当字典查找键时,它首先调用GetHashCode那个键。从这里,字典派生了内部bucket的,密钥应该在其中。然后它查看该特定存储桶中的所有密钥并调用Equals以找到正确的密钥。

于 2012-11-14T19:15:31.997 回答
1

它仍然使用覆盖的object.GetHashCode()方法来获取哈希码。有一个单独的IEquatable<T>接口的原因(即为什么默认EqualityComparer<T>不总是只调用覆盖的object.Equals()方法来比较两个对象)是出于性能原因 -object.Equals()需要一个object参数,因此实现必须先将其转换为目标类型执行有意义的比较(值类型也必须装箱和拆箱);而 to 的参数IEquatable<T>.Equals()已经是 type T。这种性能考虑不适用于该GetHashCode()方法,因为它不带参数,因此它没有理由存在于IEquatable<T>接口上。

于 2012-11-14T19:20:19.447 回答
0

字典(HashSet 和 KeyedCollections)都使用 HashBuckets(为了速度)。
HashBuckets 使用 Int32 的 GetHashCode。

如果对象不相等,则它们必须具有不同的 GetHashCode。
但是两个不相等的对象可能有相同的GetHashCode。

如果 GetHashCode 相同,则决胜局为 Equals。
GetHashCode 比较更快 - 您想避免决胜局。

你想要一个好的(独特的)GetHashCode。
如果对象来自数据库并且表具有键并且该键是 Int32(或更少),则将其用于完美的哈希码。

如果您的对象没有自然键,则可以使用系统 GetHashCode。
但是,如果您有自然键,请使用它。

所有对象都实现 Object 对象类
如果您的类没有覆盖 GetHashCode,那么它将来自 Object。

建议不要使用 Tuple 或 KeyValuePair for Key,因为它们不会产生好的 GetHashCode。很多碰撞。

于 2012-11-14T19:24:30.187 回答