• Effective C# Item10:理解GetHashCode()方法的缺陷


        GetHashCode()方法的用途:为一个基于散列的集合定义键的散列值,典型的散列集合包括HashTable和Dictionary。如果我们定义的类型在散列集中不会被用作键的话,那么不用关心它的GetHashCode()方法是否高效和正确。

        作为类型的散列值,它应该满足以下三条规则:

    1. 如果两个对象相等,那么它们必须产生相同的散列值,否则,这样的三列码不能用来查找集合中的对象。
    2. 对于任何一个对象A,A.GetHashCode()方法必须是一个实例不变式(invariant),即不管在A上调用什么方法,A.GetHashCode()都必须总是返回相同的值,,者可以确保放在“散列桶”中的对象总是位于正确的“散列桶”中。
    3. 对于所有的输入,散列函数应该在所有的整数中产生一个随机的分布,这样,我们才能从一个散列容器上获得效率的提升。

        通过上述三条规则,我们可以理解:为什么我们在重写了类型实例的Equals方法后,要重写GetHashCode()方法,因为如果不重写,会违反上述规则1。

        引用类型和值类型的基类,都对GetHashCode()方法提供了默认的实现。System.Object类的实现方式:使用一个内部字段来产生散列值,系统创建的每一个对象在创建时都会有一个唯一的对象键,这些键从1开始,每创建一个新的对象,键值就会增1,对象标识字段在对象创建后,是不可以再更改的,而GetHashCode()方法,就会将这个对象键值返回;而System.ValueType提供的默认方式:返回类型中定义的第一个字段的散列码。

       我们来分析上述默认实现是否满足了散列值的三条规则,首先,对于System.Object,在不重写Equals的情况下,是满足规则1的;规则2是可以满足的;规则3则只有在大量对象的情况下,才会满足,否则,散列值会集中在整数的低端。

       然后,我们再看ValueType,在不重写Equals,或者重写Equals并且将第一个字段作为比较条件时,是满足规则1的;如果类型中的第一个字段是只读的,那么是可以满足规则2的;至于是否可以满足规则3,就要看类型中第一个字段是否在整数中有一个随机分布了。

        我们可以自己重写GetHashCode()方法,但是一定要满足上述3条规则,其中规则1和规则2可以保证生成的散列码是正确的;规则3可以保证生成的散列码是高效的。

  • 相关阅读:
    自定义Hooks:四个典型的使用场景
    FreeSql的各种工程demo上新啦
    萌新看过来,你还学不懂VScode插件吗?
    项目7加法运算前后端分离AspNetMvcApi&Vue实现
    张高兴的 Entity Framework Core 即学即用:(一)创建第一个 EF Core 应用
    task5
    Day09参数+递归
    K8S原来如此简单(四)Service+Ingress
    别再写一堆的 for 循环了!Java 8 中的 Stream 轻松遍历树形结构,是真的牛逼!
    task23
  • 原文地址:https://www.cnblogs.com/wing011203/p/1643719.html
Copyright © 2020-2023  润新知