C#实现类型的比较示例详解

IComparable<T>

.NET 里,IComparable<T>是用来作比较的最常用接口。

如果某个类型的实例需要与该类型的其它实例进行比较或者排序的话,那么该类型就可以通过实现IComparable<T>接口来达到此目的。

IComparable<T>只提供了一个方法:

先看一个例子,这里使用了string,因为string实现了该接口:

其结果是:

string是通过按位字母进行比较的,“a”就小于“b”,所以上述str1应该是小于str2的。

而CompareTo方法返回的是int类型,而比较的结果呢,可能有三种情况:

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

再通过上面的例子,我们可以看出来:

针对x.CompareTo(y),

  • 如果 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>接口
  • 也可选去实现比较操作符。

总结

以上就是这篇文章的全部内容了,希望本文的内容对大家的学习或者工作具有一定的参考学习价值,谢谢大家对我们的支持。

(0)

相关推荐

  • 浅谈c#表达式树Expression简单类型比较demo

    实例如下: using System; using System.Linq.Expressions; class DynamicPredicate { public static Expression<Func<T, T, bool>> Generate<T>(string op) { ParameterExpression x = Expression.Parameter(typeof(T), "x"); ParameterExpression y

  • C#读取目录下所有指定类型文件的方法

    本文实例讲述了C#读取目录下所有指定类型文件的方法.分享给大家供大家参考.具体分析如下: 首先要引入命名空间:using System.IO; 再写读取方法: DirectoryInfo dir = new DirectoryInfo(path); //path为某个目录,如: "D:\Program Files" FileInfo[] inf = dir.GetFiles(); foreach (FileInfo finf in inf) { if( finf.Extension.E

  • c#数据类型基础

    1.值类型 值类型包括简单值类型和复合型类型.简单值类型可以再细分为整数类型.字符类型.实数类型和布尔类型:而复合类型则是简单类型的复合,包括结构(struct)类型和枚举(enum)类型. 整数类型 数据类型 说明 取值范围 对应于System程序集中的结构 sbyte 有符号8位整数 -128-127 SByte byte 无符号8位整数 0-255 Byte short 有符号16位整数 -32768-32767 Int16 ushort 无符号16位整数 0-65535 UInt16 I

  • C#中DateTime日期类型格式化显示方法汇总

    本文汇总了常用的DateTime日期类型格式化显示方法,方便读者在使用的时候参考借鉴一下.具体如下所示: 1.绑定时格式化日期方法: <ASP:BOUNDCOLUMN DATAFIELD= "JoinTime " DATAFORMATSTRING= "{0:yyyy-MM-dd} " > <ITEMSTYLE WIDTH= "18% " > </ITEMSTYLE > </ASP:BOUNDCOLUMN

  • c#字符串值类型与引用类型比较示例

    复制代码 代码如下: classProgram{    staticvoid Main() {        int a = 9;    //给变量a赋值为9        int b = a;   //将a的副本给变量b        b = 10;        Console.WriteLine(string.Format("a={0},b={1}", a, b));        Person ZS = newPerson();       //张三        ZS.Age

  • C#值类型和引用类型的深入理解

    从概念上看,值类型直接存储其值,而引用类型存储对其值的引用.这两种类型存储在内存的不同地方.在C#中,我们必须在设计类型的时候就决定类型实例的行为.这种决定非常重要,用<CLR via C#>作者Jeffrey Richter的话来 说,"不理解引用类型和值类型区别的程序员将会给代码引入诡异的bug和性能问题(I believe that a developer who misunderstands the difference between reference types and

  • C# 遍历枚举类型的所有元素

    比如定义了一个错误的枚举类型 复制代码 代码如下: public enum eErrorDetailCode : int         {             登陆成功 = 0,             登出 = 1,             应用错误 = 2,             成功 = 16,             失败 = 17         } 需要引用 using System; 然后在循环中,遍历枚举对象的所有元素 复制代码 代码如下: foreach (int  m

  • C#、.Net中把字符串(String)格式转换为DateTime类型的三种方法

    方式一:Convert.ToDateTime(string) 复制代码 代码如下: Convert.ToDateTime(string) 注意:string格式有要求,必须是yyyy-MM-dd hh:mm:ss 方式二:Convert.ToDateTime(string, IFormatProvider) 复制代码 代码如下: DateTimeFormatInfo dtFormat = new System.GlobalizationDateTimeFormatInfo(); dtFormat

  • C#判断一个String是否为数字类型

    方案一:Try...Catch(执行效率不高) 复制代码 代码如下: private bool IsNumberic(string oText) {     try     {         int var1=Convert.ToInt32 (oText);         return true;     }     catch     {         return false;     } } 方案二:正则表达式(推荐) a) 复制代码 代码如下: public static bool

  • 浅析C#数据类型转换的几种形式

    1.Convert.ToInt32(); //转换成32位的整数.2.变量.ToString();/最常见的转换成 字符串.3."订单"+2514 //后面的数字会转换为字符串.4.((类名A)对象名X) //强行将 对象X 转换成 A类 的对象.5.int.Parse(string);把字符串型转换成其他类型.6.还有,如果要转换成的类型为引用类型,还可以用 as teacher tea = teahcer();如 student stu = tea as student; (1)

随机推荐