我看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。其結果就是,存儲的時候你可能任性的存,在取值的時候就是你哭着找不着娘了。

好了,說了這麼多你應該對這兩個方法有了從新的認識了吧。若是仍是不明白的話,用代碼實現一下,保準明白。

相關文章
相關標籤/搜索