《Effective C 》 區別四個判等函式

2021-04-13 06:59:09 字數 3022 閱讀 4906

.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函式,而引用型別最好不要過載定義==操作符。

區別和認識四個判等函式

愚翁 李建忠blog net 有四個判等函式?不少人看到這個標題,會對此感到懷疑。事實上確是如此,net 提供了referenceequals 靜態equals 具體型別的 equals 以及 操作符這四個判等函式。但是這四個函式之間有細微的關係,改變其中乙個函式的實現會影響到其他函式的操作結果。首...

事物的四個特性和四個隔離級別

事物是一條或者多條sql語句組成的執行序列,這個序列中的所有語句都屬於同乙個工作單元,要麼同時完成,其中如果有乙個失敗,則其他操作都要回滾。事物是乙個不可分割的資料庫邏輯工作單位,要麼全部完成,要不失敗回滾。事務執行的結果必須使資料庫從乙個一致性狀態變到另乙個一致性狀態。乙個事物的執行不能被別的併發...

jsp中四個作用域的區別

jsp中四個作用域的區別 jsp內建物件作用域表 名稱作用域 在所有應用程式中有效 session 在當前會話中有效 request 在當前請求中有效 page 在當前頁面有效 首先要宣告一點,所謂 作用域 就是 資訊共享的範圍 也就是說乙個資訊能夠在多大的範圍內有效。web互動的最基本單位為htt...