2012-11-14 48 views
4

我需要用我写的密钥类型为Dictionary由默认构造函数创建的`Dictionary`是否使用哈希码?

I类阅读documentation on MSDN about the default constructor of Dictionary

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

这使得认为我必须做的唯一的事情就是我的关键类实现System.IEquatable<T>

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

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

+1

我相信c#字典实际上使用散列法 –

+1

也读取第二个链接的“备注”部分,IEquatable接口。它说:_If如果你实现'IEquatable ',你还应该重载'Object.Equals(Object)'和'GetHashCode'的基类实现,以便它们的行为与'IEquatable .Equals'方法的行为一致。如果你重写了'Object.Equals(Object)',那么你的类的静态'Equals(System.Object,System.Object)'方法的调用也会调用你重写的实现。这确保了所有'Equals'方法的调用返回一致的结果._ –

+0

是的,我注意到在看到Babak Naffas的回答后第二次阅读。其实我刚接触'.Net',看到'IEquatable'中的Equals'方法,'IEqualityComparer'中的'Equals + GetHashCode'使我认为'Equals'和'GetHashCode'不在'Object'中在'.Net'中的类(没有检查,我的不好)。我没有想到luksan的答案强调的性能问题的微妙之处,它证明了一个具有泛型参数的替代方法,因此是一个实现的通用接口。 –

回答

1

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

1

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

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

当你实现IEquatable<T>,你必须在对象覆盖EqualsGetHashCode,以配合您的IEquatable<T>实现。它不在界面中的原因是GetHashCode已经定义在object上,所有的类都来自于它,所以它在界面中并没有什么区别。

如果未能实现GetHashCode所以你IEquatable<T>实现匹配,你可能会遇到你把字典中的一个关键,但无法再找回它,因为散列码不匹配的问题:当字典查找密钥,它首先在该密钥上调用GetHashCode。从这里,字典派生内部bucket,该密钥应该在。然后,它通过该特定桶中的所有密钥,并调用Equals来查找正确的密钥。

4

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

这将是多余的System.IEquatable<T>有一个hashCode方法System.Object(其中您的实现类将隐式继承)已经提供了方法GetHashCode

0

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

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

如果GetHashCode相同,那么联合断路器就是Equals。
GetHashCode比较速度更快 - 您想避免打破平局。

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

如果您的对象没有自然键,那么可以使用系统GetHashCode。
但是,如果你有一个天然的钥匙,然后使用它。

所有对象实施对象 Object Class
如果你的类不overrite的GetHashCode那么它将来自对象。

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

相关问题