Net中對象相等比較是看似簡單實際上有點兒復雜這和現實世界的情況差不多無論人或物現實中沒有兩個絕對相等只有相對的屬性一致或同屬某個類別這學問細究下去無窮無盡一輩子也未必參得透而Net中的相等沒有那麼捉摸不透卻也值得品味一番
說到相等新手上來先學到的就是相等操作符==(有的Net語言中是單=)這個很自然問題是有不少人工作了一兩年提到相等還是只想到操作符就太片面了
在這裡茴香豆的茴字有四種寫法Net中也主要有四種相等比較分別是==操作符ObjectEquals方法ObjectReferenceEquals方法對象實例的Equals方法
先來看Object的兩個靜態方法它們邏輯比較簡單ReferenceEquals方法是比較兩個對象的引用是否相同即棧上的地址是否一樣對於值類型沒有意義參數中若有值類型參數出現必定返回false它主要用來測試實際應用開發中很少用到方法名也有點長對於引用類型如果方法結果為True這個相等是最嚴格最純粹如假包換的相等說明這兩個參數其實是同一個對象當然無論用其他哪種相等比較方式同樣也應返回True
Object的Equals靜態方法實際上是對實例Equals方法的擴展增加了null的判斷適應於比較兩個可能為空引用的對象對於值類型和Equals實例方法功能完全一樣
再來看==我們天天打交道的這小小操作符並不那麼簡單上面我們說兩個Object靜態方法區別在值類型和引用類型上對於其他相等比較區別也主要在此一般情況下不是所有對於引用類型==和ReferenceEquals靜態方法作用相同值類型在這裡則有區分對於原生值類型如intdoublelongchar等==是直接比較其數值而且不同類型間可以互相比較比如int和charA==返回的是True而對於一般的Struct如果沒有在代碼中定義==(也包括!=)操作符是不能用==比較的
引用類型也可以定義==操作符覆蓋CLR原生支持的比較最常見的是String類型它就定義了==操作符很合理地放寬了相等的條件使得String類型像原生值類型一樣按值比較String類的==操作符其實就是直接調用的被自己重寫過Equals方法
String類是最常用也最特別的一個類大部分面試都會問到String的特點除了不可變和內存駐留機制外其他主要特點就是相等的特殊性了
最後就來說說實例Equals方法吧這是個Virtual方法是我們在應用開發中經常要根據業務邏輯需要進行覆寫的方法定義並使用操作符固然方便不過除了像String之類的特殊情況引用類型讓==保持默認規則是更好的選擇而讓Equals方法實現業務上的值相等如果不覆寫Equals方法也是比較對象的引用
對於值類型實現==操作像一個點綴而如果想實現相等比較操作應該優先重寫Equals方法(同樣若要實現大小比較應該優先實現IComparable接口而不是實現比較操作符)從Object繼承的Equals方法用於值類型時比較兩個對象的所有字段全相等才為True要注意它據說用了反射效率很低的但是它低歸低為什麼一定要優先重寫它?
因為所有Net Framework鍵值集合都是用Equals實例方法做比較的所以它實際上成了Net中的法定天平無論是原生類型結構或類的實例都應以Equals方法作為其標准的相等比較方式包括我們自己實現的類型用實例方法的好處也可以理解更靈活我們可以添加一些重載的Equals方法申明不同的比較前提條件與重寫的默認Equals方法配合構成一套完整的比較規則以符合現實裡復雜多變的標准
重寫Equals方法時官方推薦重寫GetHashCode方法要是你不用此類型作鍵值集合鍵的話其實無所謂
個別情況中復雜到重載Equals方法也力不從心時我們就要定義專門用來比較相等的功能類Net Framework已經提供了一個接口SystemCollectionsIEqualityComparer並有幾個內置的實現如StringComparerEqualityComparer我們自己寫的比較類也不妨實現這個接口當然只要能用也不必計較那麼多看Net Framework源代碼能發現好多個亂七八糟的類用於比較相等大概是內部特權吧
結尾外總結一張表可以一目了然
From:http://tw.wingwit.com/Article/program/ASP/201311/21859.html