淺析C#中的IEquatable 接口


  

1、引言

  首先我們先來看看IEquatable<T>接口的出現解決了什么問題。

  我們知道,Object基類的Equals方法存在兩個明顯的問題。一是缺乏類型安全性,二是對於值類型而言需要裝箱。在本文中我們就來看下IEquatable<T> Interface是如何解決這兩個問題的。

2、IEquatable<T>接口

  我們都知道的一個事實是:如果想讓Object的Equals方法為所有派生類型所用,那么,它的參數就必須設計成object類型。

  object是引用類型,這就意味着,如果傳遞一個值類型的參數,那么該參數將被裝箱,這就會造成性能損失。

  另外,還存在另一個問題:將object類型設為參數還意味着類型安全性的缺失。

  解決裝箱和類型安全性問題的一個辦法就是定義一個新的Equals方法,該方法接受一個和待比較類型相同類型的參數。例如,對於字符串類型而言,定義一個接受string類型的Equals方法就能圓滿解決這兩個問題。

  但這會面臨另一個新的問題,那就是:定義強類型的方法和OOP中的繼承存在根本的沖突。我們不能在Object基類中定義一個強類型的Equals方法,因為Object基類根本無法知曉派生類的類型。

  那么,我們怎么樣才能定義一個強類型的Equals方法,同時該方法能被所有類型使用呢?微軟解決這個問題的思路就是通過提供一個IEquatable<T>接口,該接口向所有類型暴露。查看該接口的定義時,可以發現它僅暴露了一個Equals方法,如下所示。

using System;

namespace System
{
    public interface IEquatable<T>
    {
        bool Equals(T other);
    }
}

  該Equals方法和Object基類的虛Equals方法的作用相同,只不過它接受一個T類型參數,因此,它是強類型的,這意味着對於值類型而言,不存在裝箱的問題。

3、IEquatable<T>接口和值類型 

  我們可以通過一個簡單的例子來證明IEquatable<T>接口的使用。

static void Main(String[] args)  
       {  
           int number1 = 1;  
           int number2 = 2;  
           int number3 = 1;  
  
           Console.WriteLine(number1.Equals(number2));  
           Console.WriteLine(number1.Equals(number3));  
  
       }   

  在上面的例子中,我們定義了三個整型變量,然后使用Equals方法進行比較。在VS中借助智能感知,可以發現對於int類型而言存在兩個Equals方法,一個接受object參數,另一個接受int類型參數。接受int參數的Equals方法實現了IEquatable<T>接口,其中,T為int類型。因為我們在調用Equals方法時傳遞的是一個int類型變量,而不是一個object變量,因此,編譯器將選擇實現了IEquatable<T>接口的Equals方法。

  在平常開發中對於int類型的比較,我們不會像上面那樣使用Equals方法進行比較,而是使用更加簡便明了的==操作符。

  所有的基元類型都提供了對IEquatable<T>接口的實現,就像上面代碼中的int類型那樣,int類型實現了IEquatable<int>。

  總體而言,IEquatable<T>接口對值類型非常有用。但微軟並沒有為FCL中的非基元的值類型實現該接口,因此,不能寄希望於對FCL中值類型而言總是可以使用該接口。

4、IEquatable<T>和引用類型

  對於引用類型而言,IEquatable<T>接口並沒有那么有用。一是因為引用類型不存在像值類型那樣的由裝箱導致的性能問題,二是因為IEquatable<T>接口不能很好地處理繼承問題。

  但值的注意的是,String類型實現了IEquatable<T>接口,如下面所示

static void Main(String[] args)  
        {  
            string s1 = "Hello World";  
            string s2 = string.Copy(s1);  
              
            Console.WriteLine(s1.Equals(s2);  
  
        }   

  上面的代碼中,C#編譯器將直接選擇強類型的Equals方法。另外,String類型是sealed的,因此,你不能從它繼承。這樣,在相等性判定和繼承之間的沖突就不存在了。

  很明顯,若一個類型定義了兩個Equals方法,我們希望它們對相同的輸入,產生相同的輸出。關於這一點,微軟提供的默認實現都嚴格履行了這一點。當我們自己去實現IEquatable<T>接口時,也要保證這一點。否則,別的開發者使用你定義的類型時將感到困惑。


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM