Equals 判断两个对象是否相等,可以使用 Equals ,通过它可以判断出两个对象是否具有相同的数据。在 object 中这个方法只是调用了 ReferenceEquals 方法来判断同一性,因此在必要的时候我们必须重写 Equals 方法。一般来说重写 Equals 方法常用的步骤如下:

检查对象是否为 null ;

判断是否是引用类型,如果是就判断引用是否相等;

判断数据类型是否相等;

调用具体类型的辅助方法,参数必须是要比较的类型;

判断哈希码是否相等,这一步需进行短路操作和字段比较;

在基类的 Equals 方法被重写的前提下,必须检查基类的 Equals 方法;

判断关键字段的值是否相等;

重写 GetHashCode 方法;

重写 == 、 != 操作符。

Tip: 如果类型是密封类型,那么第三步可以省略掉。

我们不仅需要按照上述的步骤重写 Equals 方法,还需要注意如下几点:

GetHashCode 方法不一定返回的是独一无二的值,因此我们不能仅仅依赖它的返回值来判断两个对象是否相等;

我们不能在 GetHashCode 和 Equals 中引发任何异常;

必须保证对象之间可以随意比较,且不能触发任何异常;

必须实现重写 Equals 、 GetHashCode 、 == 和 != ,且重写的算法必须相同;

尽量不要在可变类型上重写相等性操作符。

三、 GetHashCode

在上一小节中我们也注意到在重写 Equals 过程中我们需要重写 GetHashCode 方法。 所谓 Hash Code 就是用来生成和对象值对应的数字,从而高效的平衡哈希表的作用。 重写 GetHashCode 方法是比较困难的,下面我就来详细讲解一下重写规则、方法和注意事项。重写 GetHashCode 方法需要从性能、安全方面考虑,同时也需要满足一些要求。

性能 由于哈希码的返回值是 int 类型,因此会出现部分对象包含的值比 int 取值范围大的情况,这时哈希码就肯定会存在重复的情况,所以这时我们要保证哈希码的返回值尽可能的唯一。此外针对哈希码的算法我们要尽可能的保证返回的哈希码应当在 int 类型取值范围内平均分布。在 Equals 中利用 GetHashCode 方法进行短路操作时我们必须对算法的性能进行优化,避免将类型作为字典集合中的键类型使用,因为这会导致频繁的调用 GetHashCode 方法。在设计 GetHashCode 的算法时应保证良好的平衡性,即无论哈希表如何对哈希值进行 bucketing,也不会破坏平衡性。一般来说最理想的状态是两个对象间 1 bit 的差异应该造成哈希码 16 bit 的差异。