( 轉 ) 聊一聊C#的Equals()和GetHashCode()方法
博客創建一年多,還是第一次寫博文,有什麽不對的地方還請多多指教。
關於這次寫的內容可以說是老生長談,百度一搜一大堆。大神可自行繞路。
最近在看Jeffrey Richter的CLR Via C#,在看到GetHashCode()方法的時候,有一個地方不是特別明白,就是重寫Equals()方法時為什麽要把GetHashCode()方法一塊重寫(不重寫也沒關系,但是微軟會發送一條警告)。在解釋這個問題之前需要先把Equals()和GetHashCode()方法進行深入了解。
首先先談一下Equals()這個方法:
Equals()方法,來自於Object,是我們經常需要重寫的方法。此方法的默認實現大概是這樣的:
public virtual bool Equals(object obj) { if(obj==null) return false; if(GetType() != obj.GetType()) return false; Return true; }
由此可以看出,默認的實現其實比較的是兩個對象的內存地址(==操作符默認比較內存地址)。值類型和string類型除外,因為所有值類型繼承於System.ValueType()(System.ValueType()同樣繼承於Object,但是System.ValueType()本身卻是引用類型),而System.ValueType()對Equals()和==操作符進行了重寫,是逐字節比較的。而string類型是比較特殊的引用類型,所以strIng在很多地方都是特殊處理的,此處就不做深究了。
Ps:按Jeffrey Richter的說法,在值類型使用Equals()時,因為Equals()使用了反射,在比較時會影響效率。
說完Equals()後再來聊一聊GetHashCode()。
其實GetHashCode()在操作值類型的時候也是被System.ValueType()重寫的。經過樓主測試的幾個常用值類型來看,值類型的GetHashCode()基本都是原值輸出(特指整數,Int32除外),真實性有待驗證。結果如下:
說完值類型,說一下引用類型,先看下面這張運行結果:
從上圖的結果可以看出,雖然string是引用類型,但是只要值一樣,返回的HashCode也是一樣的,這取決於它的特殊性。而我們自己寫的類型Coordinates同樣的值但返回的HashCode卻不一樣,我們可以簡單的理解為是coor1與coor2的內存地址不同,所以CLR認為它們是不一樣的。
Ps:在程序的生命周期中,相同的對象、變量返回的HashCode是相同的,並且是唯一的。但是絕對不允許做持久性存儲,程序一旦結束並重新啟動後,同樣的對象無法獲得上次程序運行時的HashCode。
了解了兩個方法後,開始今天的重點話題。
其實在上面的兩個對象中(coor1、coor2),coor1.Equals(coor2)的返回結果為false(因為內存地址不同),如果我們想讓它們的返回結果為true的話,只能重寫Equals方法(如下圖)。
重點來了,重寫完Equals以後,vs發出了警告,雖然程序猿從來都是無視警告的,但這個警告確實有必要了解一下,先來看下面這三段代碼。
代碼段一、二:
代碼段三:
看完這三段代碼,應該就理解為什麽要重寫Equal時有必要重寫GetHashCode了。
當然,如果你沒打算在代碼中使用Dictionary或HashTable就無所謂寫不寫了,換句話說,如果要把引用類型做為Dictionary或HashTable的key使用時,必須重寫這兩個方法。
原因:當我們把引用類型(string除外)做為Dictionary或HashTable的key時,有可能永遠無法根據Key獲得value的值,或者說兩個類型的HashCode永遠不會相等。就拿Dictionary來說,雖然我們存儲的時候是鍵值對,但是CLR會先把key轉成HashCode並且驗證Equals後再做存儲,根據key取值的時候也是把key轉換成HashCode並且驗證Equals後再取值,一定要註意驗證時HashCode和Equals的關系是並且(&&)的關系。也就是說,只要GetHashCode和Equlas中有一個方法沒有重寫,在驗證時沒有重寫的那個方法會調用基類的默認實現,而這兩個方法的默認實現都是根據內存地址判斷的,也就是說,其實一個方法的返回值永遠會是false。其結果就是,存儲的時候你可能任性的存,在取值的時候就是你哭著找不著娘了。
好了,說了這麽多你應該對這兩個方法有了重新的認識了吧。如果還是不明白的話,用代碼實現一下,保準明白。
原貼:http://www.cnblogs.com/xiaochen-vip8/articles/5506478.html
( 轉 ) 聊一聊C#的Equals()和GetHashCode()方法