從《Microsoft.net框架程序設(shè)計(jì)》一書中,看到Equals的實(shí)現(xiàn)基本分為如下三類(順序有所調(diào)整):(1)引用類型,從MyRefType到Object的繼承鏈上(基類、基類的基類、...),有類覆蓋了Object的Equals方法實(shí)現(xiàn);(2)引用類型,從MyRefType到Object的繼承鏈上(基類、基類的基類、...),均沒有類覆蓋Object的Equals方法實(shí)現(xiàn);(3)值類型的Equals方法實(shí)現(xiàn)。分法相當(dāng)科學(xué),不過我看了其中的代碼實(shí)現(xiàn),針對(duì)第二種實(shí)現(xiàn)有一些自己的疑惑和想法。為了沒有看過該書的同仁們更好地理解,我將書中的實(shí)現(xiàn)貼在此文中。先看書中第一種,(1)引用類型,從MyRefType到Object的繼承鏈上(基類、基類的基類、...),有類覆蓋了Object的Equals方法的實(shí)現(xiàn):
其中用到了Object的Equals方法,將原代碼貼出來
在這種實(shí)現(xiàn)中,個(gè)人認(rèn)為Equals方法是沒有問題的,首先調(diào)用
比較了基類的部分,然后就比較自己的部分就OK了。再看書中的第二種,2)引用類型,從MyRefType到Object的繼承鏈上(基類、基類的基類、...),均沒有類覆蓋Object的Equals方法的實(shí)現(xiàn);
我們可以發(fā)現(xiàn),同第一種實(shí)現(xiàn)的差別在于沒有了如下代碼段:
為什么不能加這一段呢?因?yàn)樵谶@種實(shí)現(xiàn)環(huán)境下,我們?cè)O(shè)定了前提:從MyRefType到Object的繼承鏈上,均沒有類覆蓋Object的Equals方法。所以如果加了上面這段代碼,那實(shí)際調(diào)用的是Object類的實(shí)例方法Equals
這樣,如果this和obj不指向同一個(gè)對(duì)象,則這個(gè)base.Equals(obj)肯定返回false,于是Equals也返回false,而在this和obj指向同一個(gè)對(duì)象,Equals返回true,這樣不就是Object的Equals()實(shí)現(xiàn)嗎?既然如此,何苦自己重新這個(gè)函數(shù)呢?既然重寫了,那肯定有不一樣的行為,于是下面的代碼段加入不得。
到這里,我們也可以理解。不過問題是,沒有加入這段代碼,從“(2)引用類型,從MyRefType到Object的繼承鏈上(基類、基類的基類、...),均沒有類覆蓋Object的Equals方法的實(shí)現(xiàn)”中,我們好像找不到比較基類成員的影子。不比較基類成員,是否合理呢?看下面例子,如果兩個(gè)Derived對(duì)象,無需比較Base部分的成員變量,那么下面的寫法是正確的,此時(shí)該程序打印出的結(jié)果為True。
但是有時(shí)邏輯要求,兩個(gè)Derived對(duì)象需要比較Base部分的成員變量,那上面的寫法就是錯(cuò)誤的,此時(shí)應(yīng)該修改為如下的代碼,該程序打印出的結(jié)果為False。
再看第三種實(shí)現(xiàn):(3)值類型的Equals方法實(shí)現(xiàn)。書中代碼如下:
這種實(shí)現(xiàn)方法,如果不存在其它類對(duì)MyValType的隱式類型轉(zhuǎn)換,是沒有問題的,如果存在隱式類型轉(zhuǎn)換,那代碼中的強(qiáng)類型Equals()方法(從第16行開始)就可能存在問題了。試想想,兩種不同類型的實(shí)例,我們有多少場(chǎng)合會(huì)認(rèn)為他們Equals呢?根據(jù)邏輯來定,一般不會(huì)認(rèn)為它們相同。為了說明存在的這個(gè)問題,請(qǐng)看如下代碼:
上面代碼中,一般從常理來說,我們不會(huì)認(rèn)為myValue1和myValue2相等,因?yàn)樗麄兪遣煌愋偷膶?shí)例(myValue1屬于MyValType類型,myValue2屬于MyValType2類型)。但是實(shí)際輸出了結(jié)果True。個(gè)中原因在于定義了一個(gè)從MyValType2到MyValType的隱式轉(zhuǎn)換:
于是在運(yùn)行語句myValue1.Equals(myValue2)時(shí),會(huì)先將myValue2轉(zhuǎn)換為一個(gè)MyValType類型的臨時(shí)變量,然后用MyValue1和這個(gè)臨時(shí)變量比較,此時(shí)調(diào)用強(qiáng)類型的比較函數(shù),因?yàn)镸yValType和MyValType2這兩個(gè)類型內(nèi)部結(jié)構(gòu)一樣,且兩變量的內(nèi)部field的值相同,所以返回True。上面例子說明 ,如果不能確保沒有其他類型到該類型的隱式轉(zhuǎn)換,那萬無一失的辦法就是不實(shí)現(xiàn)強(qiáng)類型的Equals。調(diào)用默認(rèn)的Equals方法或者實(shí)現(xiàn)參數(shù)為Object的Equals方法,雖然效率可能差一點(diǎn),但是可靠。當(dāng)然,如果可以確認(rèn)沒有其他類型到該類型的隱式轉(zhuǎn)換,那實(shí)現(xiàn)強(qiáng)類型的Equals方法還是可以帶來效率的提升。(相同描述可參見《.net框架程序設(shè)計(jì)》)。關(guān)于Equals()方法的實(shí)現(xiàn),基本上也就到此結(jié)束了。如果各位有什么好的心得,歡迎積極探討。
posted on 2009-04-26 23:33 五味雜陳 閱讀(1550) 評(píng)論(0) 編輯 收藏 引用 所屬分類: .NET
Powered by: C++博客 Copyright © 五味雜陳