**:愚翁
(李建忠blog)
.net
有四個判等函式?不少人看到這個標題,會對此感到懷疑。事實上確是如此,
.net
提供了referenceequals
、靜態equals
,具體型別的
equals
以及==
操作符這四個判等函式。但是這四個函式之間有細微的關係,改變其中乙個函式的實現會影響到其他函式的操作結果。
首先要說的是
object.referenceequals
和object.equals
這兩個靜態函式,對於它們倆來說,是不需要進行重寫的,因為它們已經完成它們所要得做的操作。
對於object.referenceequals
這個靜態函式,函式形勢如下:
public static bool referenceequals( object left, object right );
這個函式就是判斷兩個引用型別物件是否指向同乙個位址。有此說明後,就確定了它的使用範圍,即只能對於引用型別操作。那麼對於任何值型別資料操作,即使是與自身的判別,都會返回
false
。這主要因為在呼叫此函式的時候,值型別資料要進行裝箱操作,也就是對於如下的形式來說。
int n = 10;
object.referenceequals( n, n );
這是因為對於
n這個資料裝箱兩次,而每次裝箱後的位址有不同,而造成
object.referenceequals( n, n )
的結果永遠為
false
。對於第乙個判等函式來說,沒有什麼好擴充套件的,因為本身已經很好地完成了它所要做的。
對於第二個
object.equals
這個靜態函式,其形式如下:
public static bool equals( object left, object right );
按照書中對它的分析,其大致函式**如下:
public
static
void equals( object left, object right )
可以說,
object.equals
這個函式完成判等操作,需要經過三個步驟,第一步是需要根據物件所屬型別的
==操作符的執行結果;第二步是判別是否為
null
,也是和第一步一樣,需要根據型別的
==操作符的執行結果;最後一步要使用到型別的
equals
函式的執行結果。也就是說這個靜態函式的返回結果,要取決於後面要提到的兩個判等函式。型別是否提供相應的判等函式,成為這個函式返回結果的重要因素。
那麼對於
object.equals
這個靜態方法來說,雖說接受引數的型別也屬於引用型別,但是不同於
object.referenceequals
函式,對於如下的**,能得出正確的結果。
int n = 10;
debug.writeline( string.format( "", object.equals( n, n ) ) );
debug.writeline( string.format( "", object.equals( n, 10 ) ) );
這是因為在此函式中要用到具體型別的兩個判等函式,不過就函式本身而言,該做的判斷都做了,因此不需要去過載新增複雜的操作。
為了更好的述說剩下兩個函式,先解釋一下等價的意義。對於等價的意義,就是自反、對稱以及傳遞。
所謂自反,即
a == a
;而對稱,是
a == b
,則b == a
;傳遞是
a == b
,b == c
,則a == c
;理解等價的意義後,那麼在實現型別的判等函式也要滿足這個等價規則。
對於可以過載的兩個判等函式,首先來介紹的是型別的
equals
函式,其大致形式如下:
public override bool equals( object right );
那麼對於乙個型別的
equals
要做些什麼操作呢,一般來說大致如下:
public
class keydata
set }
public
override
bool equals( object right )
}
如上增加了乙個型別檢查,即
if( this.gettype() != right.gettype() )
這部分,這是由於子類物件可以通過
as轉化成基類物件,從而造成不同型別物件可以進行判等操作,違反了等價關係。
除此外對於型別的
equals
函式來,其實並沒有限制型別非要屬於引用型別,對於值型別也是可以過載此函式,但是我並不推薦,主要是
equals
函式的引數型別是不可變的,也就是說通過此方法,值型別要經過裝箱操作,而這是比較影響效率的。
而對於值型別來說,我推薦使用最後一種判等函式,即過載運算子
==函式,其大致形式如下:
public static bool operator == ( keydata left,keydata right );
對於乙個值型別而言,其的大致形式應該如下:
public
struct keydata
set }
public
static
bool
operator == ( keydata left,keydata right )
public
static
bool
operator != ( keydata left, keydata right )
}
由於
==操作與
!=操作要同步定義,所以在定義
==過載函式的時候,也要定義
!=過載函式。這也是
.net
在判等操作保持一致性。那麼對於最後乙個判等函式,這種過載運算子的方法並不適合引用型別。這就是
.net
經常現象,去判斷兩個引用型別,不要用
==,而要用某個物件的
equals
函式。所以在編寫自己型別的時候,要保留這種風格。
那麼對於以上介紹的四種判等函式,會產生如下類似的對比**。
操作結果取決於
適用範圍
建議object.referenceequals
兩個引數物件是否屬於同乙個引用
引用型別
不要用它來判斷值型別資料
object.equals
引數型別自身的判等函式
無限制
考慮裝箱操作對值型別資料產生的影響
型別的equals
型別過載函式
無限制
考慮裝箱操作對值型別資料產生的影響
型別的==過載
型別過載函式
無限制
不要在引用型別中過載此運算子
那麼在編寫型別判等函式的時候,要注意些什麼呢,給出如下幾點建議。
首先,要判斷當前定義的型別是否具有判等的意義;
其次,定義型別的判等函式要滿足等價規則;
最後一點,值型別最好不要過載定義
equals
函式,而引用型別最好不要過載定義
==操作符。
《Effective C 》 區別四個判等函式
net有四個判等函式?不少人看到這個標題,會對此感到懷疑。事實上確是如此,net提供了referenceequals 靜態equals,具體型別的equals以及 操作符這四個判等函式。但是這四個函式之間有細微的關係,改變其中乙個函式的實現會影響到其他函式的操作結果。首先要說的是object.ref...
認識事物的四個階段
size medium 我們的工作生活中總是有各種事物需要認識,規律需要掌握。工作中對哲學的思考是否有幫助呢?答曰 有幫助。但不可以過度追求和捨本逐末,正如先知指向天空說這是月亮,而我們不可以誤解其手指是月亮 而如果是真正智慧型的先知也會先點撥手指和指示是什麼。階段一 看山是山 看水是水 最淺層認識...
認識UWB的四個誤區
誤區一 uwb只能短距離執行 這種理解是不正確的。雖然uwb在技術上是一種短程無線技術 如藍芽 wifi和nfc 但這實際上更像是乙個類別列表。uwb的工作頻率介於6.5ghz和10ghz之間,而藍芽的固定頻率為2.4ghz。一般規律是頻率越高,距離越短。然而,在條件允許下,uwb的工作範圍可以延伸...