区别和认识四个判等函数
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 )
??? {
??????? // Check object identity
??????? if( left == right )
??????????? return true;
?
??????? // both null references handled above
??????? if( ( left == null ) || ( right == null ) )
??????????? return false;
?
??????? return left.Equals( right );
??? }
?
可以說,Object.Equals這個函數完成判等操作,需要經過三個步驟,第一步是需要根據對象所屬類型的==操作符的執行結果;第二步是判別是否為null,也是和第一步一樣,需要根據類型的==操作符的執行結果;最后一步要使用到類型的Equals函數的執行結果。也就是說這個靜態函數的返回結果,要取決于后面要提到的兩個判等函數。類型是否提供相應的判等函數,成為這個函數返回結果的重要因素。
?
那么對于Object.Equals這個靜態方法來說,雖說接受參數的類型也屬于引用類型,但是不同于Object.ReferenceEquals函數,對于如下的代碼,能得出正確的結果。
??? int n = 10;
??? Debug.WriteLine( string.Format( "{0}", Object.Equals( n, n ) ) );
??? Debug.WriteLine( string.Format( "{0}", 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
??? {
??????? private int nData;
??????? public int Data
??????? {
??????????? get{ return nData;}
??????????? set{ nData = value; }
??????? }
?
??????? public override bool Equals( object right )
??????? {
??????????? //Check null
??????????? if( right == null )
??????????????? return false;
?
??????????? //check reference equality
??????????? if( object.ReferenceEquals( this, right ) )
??????????????? return true;
?
??????????? //check type
??????????? if( this.GetType() != right.GetType() )
??????????????? return false;
?
??????????? //convert to current type
??????????? KeyData rightASKeyData = right as KeyData;
?
??????????? //check members value
??????????? return this.Data == rightASKeyData.Data;
??????? }
??? }
?
如上增加了一個類型檢查,即
if( this.GetType() != right.GetType() )
這部分,這是由于子類對象可以通過as轉化成基類對象,從而造成不同類型對象可以進行判等操作,違反了等價關系。
?
除此外對于類型的Equals函數來,其實并沒有限制類型非要屬于引用類型,對于值類型也是可以重載此函數,但是我并不推薦,主要是Equals函數的參數類型是不可變的,也就是說通過此方法,值類型要經過裝箱操作,而這是比較影響效率的。
?
而對于值類型來說,我推薦使用最后一種判等函數,即重載運算符==函數,其大致形式如下:
public static bool operator == ( KeyData left,? KeyData right );
?
對于一個值類型而言,其的大致形式應該如下:
??? public struct KeyData
??? {
??????? private int nData;
??????? public int Data
??????? {
??????????? get{ return nData;}
??????????? set{ nData = value; }
??????? }
?
??????? public static bool operator == ( KeyData left,? KeyData right )
??????? {
??????????? return left.Data == right.Data;
??????? }
?
??????? public static bool operator != ( KeyData left, KeyData right )
??????? {
??????????? return left.Data != right.Data;
??????? }
??? }
?
由于==操作與!=操作要同步定義,所以在定義==重載函數的時候,也要定義!=重載函數。這也是.Net在判等操作保持一致性。那么對于最后一個判等函數,這種重載運算符的方法并不適合引用類型。這就是.Net經?,F象,去判斷兩個引用類型,不要用==,而要用某個對象的Equals函數。所以在編寫自己類型的時候,要保留這種風格。
?
那么對于以上介紹的四種判等函數,會產生如下類似的對比表格。
?
?操作結果取決于
?適用范圍
?建議
?
Object.ReferenceEquals
?兩個參數對象是否屬于同一個引用
?引用類型
?不要用它來判斷值類型數據
?
Object.Equals
?參數類型自身的判等函數
?無限制
?考慮裝箱操作對值類型數據產生的影響
?
類型的Equals
?類型重載函數
?無限制
?考慮裝箱操作對值類型數據產生的影響
?
類型的==重載
?類型重載函數
?無限制
?不要在引用類型中重載此運算符
?
?
那么在編寫類型判等函數的時候,要注意些什么呢,給出如下幾點建議。
首先,要判斷當前定義的類型是否具有判等的意義;
其次,定義類型的判等函數要滿足等價規則;
最后一點,值類型最好不要重載定義Equals函數,而引用類型最好不要重載定義==操作符。
?
本文來自CSDN博客,轉載請標明出處:http://blog.csdn.net/Knight94/archive/2006/08/11/1050901.aspx
總結
以上是生活随笔為你收集整理的区别和认识四个判等函数的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: 火狐启动速度慢
- 下一篇: 根据信号灯状态解决网络故障