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>接口
  • 也可选去实现比较操做符。
相关文章
相关标签/搜索