C# - 實現類型的比較

IComparable<T>

.NET 裏,IComparable<T>是用來做比較的最經常使用接口。安全

若是某個類型的實例須要與該類型的其它實例進行比較或者排序的話,那麼該類型就能夠經過實現IComparable<T>接口來達到此目的。spa

IComparable<T>只提供了一個方法:插件

 

先看一個例子,這裏使用了string,由於string實現了該接口:3d

其結果是:blog

string是經過按位字母進行比較的,「a」就小於「b」,因此上述str1應該是小於str2的。排序

而CompareTo方法返回的是int類型,而比較的結果呢,可能有三種狀況:繼承

  • x == y
  • x < y
  • x > y

再經過上面的例子,咱們能夠看出來:接口

針對x.CompareTo(y),string

  • 若是 x == y,那麼 結果 = 0
  • 若是 x < y,那麼結果 < 0
  • 若是 x > y,那麼結果 > 0

 

咱們能夠把代碼重構一下,提取出一個低級別方法,便於邏輯複用:編譯

 

順便提一下,string並無實現> < == 等等操做符。

 

int

全部的原始類型都實現了IComparable<T>。

因此使用上面的方法,也能夠比較原始數據類型:

 

固然這些類型也可使用操做符,例如:

而string沒有實現這些操做符,因此這樣寫就是錯誤的:

 

相等性 vs 比較

直接看圖:

其中,針對比較性,System.object並無支持,由於對於大多數類型而言,對它們的實例進行比較排序是沒有意義的。

例如3 < 4,這樣就是合理的;而提交按鈕 < 取消按鈕,這就沒有意義了;這個委託 < 另外一個委託,這也沒有意義。

針對相等性而言,IEquatable<T>僅僅就是對object裏的那些Equals方法的補充。而針對比較性而言,IComparable<T>是主打的方式。

其它的方式都有對應。

下面兩個黃色的經過」插件的方式「實現的,這裏只提一下,不介紹了。

 

比較性 只比較值

判斷相等性的時候,可能判斷的是引用相等或者是值相等。

而進行比較排序的時候,其比較的只能是值,由於對引用進行比較排序是沒有意義的。

 

而==和!=操做符能夠爲原始數據類型和引用類型來使用,而>, <, >=, <= 只能用於原始數據類型。

 

在自定義類型上實現比較

其實我一般不在個人類型上去實現IComparable<T>,包括引用類型和原始類型。

由於是這樣的,好比說有一個Person(人)這個類型,我想對它排序,按照年齡排序,能夠;按照姓名排序,也能夠;按照身高排序,也能夠;可是沒有任何一種排序對人來講是最理所固然的。

更好的辦法是實現某種比較器。

可是有時候仍是須要實現IComparable<T>,那麼下面就講一下怎麼作。

 

值類型

Person Struct:

若是直接使用咱們以前的方法,則會報錯:

由於它沒實現IComparable<T>接口。

使用大於號小於號的話,也會報錯:

由於這個類型也沒有實現比較操做符。

 

實現IComparable<T>接口

很簡單,直接調用了字段Height的CompareTo方法,由於int類型實現了IComparable<T>接口。

 

實現比較操做符

一共四個操做符:<, >, <=, >=,必須都得實現。

代碼是:

這個很簡單就不解釋了。

 

如今代碼不會報錯了:

其運行結果是:

 

運行OK了,看似沒問題,而後,還有一個問題:

使用等號判斷相等性的代碼會報錯。

 

若是你不是用==操做符的話,那麼代碼是沒問題的,也是能夠進行比較的,也沒人強制要求實現==和!=操做符。可是這很奇怪!由於你說 p1 > p2,這個成立,而後再說 p1 != p2這個就編譯錯誤,那就不合理了。

因此,若是你實現了比較操做符,那麼相等性操做符也應該一同實現了:

那麼既然==和!=都實現了,那麼其它的相等性判斷方法也應該一同實現:

  • object.Equals()
  • object.GetHashCode()
  • IEquatable<T>

看起來挺麻煩,但這只是一個struct,仍是相對簡單的。。。。

 

但針對struct,其實還沒完,還有一個非泛型的IComparable接口,泛型出現以前,一直都是用這個接口的。

這個接口如今來講沒什麼用了,可是若是有其它遺留的老代碼須要使用你這個struct,你可能還須要把這個接口實現一下。。。😂

 

引用類型

引用類型除了須要考慮上面struct考慮的那些東西外,還須要考慮更多的東西。

首先,須要在CompareTo裏面檢查是否爲null,和類型檢查。

而若是Person是一個沒有seal的class,那問題就更大了,之前文章裏提到的OOP繼承問題、類型安全問題、相等性問題將所有出現。由於類型安全和比較性仍是無法一塊兒很愉快的工做。反正會很混亂。。。

 

因此若是事seal的class,那麼在其上實現比較性的話還勉強能夠接受;不然的話,祝好運。。。

 

泛型

以前在相等性的文章裏,提到過,針對泛型代碼來講,==和!=操做符不能很好的工做,而object.Equals()卻能夠。

這點在比較性裏面也是同樣的。針對泛型的比較,你須要使用IComparable<T>.CompareTo()方法,而不是比較的操做符>, <, >=, <=等(即便實現了比較操做符)。

 

若是我把以前的方法代碼改爲使用比較操做符:

那麼就會報錯,由於沒法約束泛型實現了某些操做符。。。但能夠考慮在接口裏面實現比較操做符。。。

 

可是實現比較性的話:

  • 實現IComparable<T>接口
  • 也可選去實現比較操做符。
相關文章
相關標籤/搜索