C#區別和認識四個判等函數

來源:互聯網
上載者:User

.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經常現象,去判斷兩個參考型別,不要用==,而要用某個對象的Equals函數。所以在編寫自己類型的時候,要保留這種風格。

  那麼對於以上介紹的四種判等函數,會產生如下類似的對比表格。操作結果取決於 適用範圍 建議Object.ReferenceEquals 兩個參數對象是否屬於同一個引用 參考型別 不要用它來判斷實值型別資料Object.Equals 參數類型自身的判等函數 無限制 考慮裝箱操作對實值型別資料產生的影響類型的Equals 類型重載函數 無限制 考慮裝箱操作對實值型別資料產生的影響類型的==重載 類型重載函數 無限制 不要在參考型別中重載此運算子;那麼在編寫類型判等函數的時候,要注意些什麼呢,給出如下幾點建議。
  首先,要判斷當前定義的類型是否具有判等的意義;
  其次,定義類型的判等函數要滿足等價規則;
  最後一點,實值型別最好不要重載定義Equals函數,而參考型別最好不要重載定義==操作符。

相關文章

聯繫我們

該頁面正文內容均來源於網絡整理,並不代表阿里雲官方的觀點,該頁面所提到的產品和服務也與阿里云無關,如果該頁面內容對您造成了困擾,歡迎寫郵件給我們,收到郵件我們將在5個工作日內處理。

如果您發現本社區中有涉嫌抄襲的內容,歡迎發送郵件至: info-contact@alibabacloud.com 進行舉報並提供相關證據,工作人員會在 5 個工作天內聯絡您,一經查實,本站將立刻刪除涉嫌侵權內容。

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.