我看C#的Equals()和GetHashCode()方法

首先先谈一下Equals()这个方法:测试

Equals()方法,来自于Object,是咱们常常须要重写的方法。此方法的默认实现大概是这样的:spa

 1 public virtual bool Equals(object obj)
 2 
 3 {
 4 
 5   if(obj==null) return false;
 6 
 7   if(GetType() != obj.GetType()) return false;
 8 
 9   Return true;
10 
11 }

由此能够看出,默认的实现其实比较的是两个对象的内存地址(==操做符默认比较内存地址)。值类型和string类型除外,由于全部值类型继承于System.ValueType()(System.ValueType()一样继承于Object,可是System.ValueType()自己倒是引用类型),而System.ValueType()Equals()==操做符进行了重写,是逐字节比较的。而string类型是比较特殊的引用类型,因此strIng在不少地方都是特殊处理的,此处就不作深究了。3d

说完Equals()后再来聊一聊GetHashCode()code

 

其实GetHashCode()在操做值类型的时候也是被System.ValueType()重写的。通过楼主测试的几个经常使用值类型来看,值类型的GetHashCode()基本都是原值输出(特指整数,Int32除外),真实性有待验证。结果以下:对象

 

说完值类型,说一下引用类型,先看下面这张运行结果:blog

从上图的结果能够看出,虽然string是引用类型,可是只要值同样,返回的HashCode也是同样的,这取决于它的特殊性。而咱们本身写的类型Coordinates一样的值但返回的HashCode却不同,咱们能够简单的理解为是coor1coor2的内存地址不一样,因此CLR认为它们是不同的。继承

Ps:在程序的生命周期中,相同的对象、变量返回的HashCode是相同的,而且是惟一的。可是绝对不容许作持久性存储,程序一旦结束并从新启动后,一样的对象没法得到上次程序运行时的HashCode生命周期

了解了两个方法后,开始今天的重点话题。内存

其实在上面的两个对象中(coor1coor2)coor1.Equals(coor2)的返回结果为false(由于内存地址不一样),若是咱们想让它们的返回结果为true的话,只能重写Equals方法(以下图)string

 

重点来了,重写完Equals之后,vs发出了警告,虽然程序猿历来都是无视警告的,但这个警告确实有必要了解一下,先来看下面这三段代码。

 

看完这三段代码,应该就理解为何要重写Equal时有必要重写GetHashCode了。

固然,若是你没打算在代码中使用DictionaryHashTable就无所谓写不写了,换句话说,若是要把引用类型作为DictionaryHashTablekey使用时,必须重写这两个方法。

缘由:当咱们把引用类型(string除外)作为DictionaryHashTablekey时,有可能永远没法根据Key得到value的值,或者说两个类型的HashCode永远不会相等。就拿Dictionary来讲,虽然咱们存储的时候是键值对,可是CLR会先把key转成HashCode而且验证Equals后再作存储,根据key取值的时候也是把key转换成HashCode而且验证Equals后再取值,必定要注意验证时HashCodeEquals的关系是而且(&&)的关系。也就是说,只要GetHashCodeEqulas中有一个方法没有重写,在验证时没有重写的那个方法会调用基类的默认实现,而这两个方法的默认实现都是根据内存地址判断的,也就是说,其实一个方法的返回值永远会是false。其结果就是,存储的时候你可能任性的存,在取值的时候就是你哭着找不着娘了。

好了,说了这么多你应该对这两个方法有了从新的认识了吧。若是仍是不明白的话,用代码实现一下,保准明白。

相关文章
相关标签/搜索