欢迎来到.net学习网

欢迎联系站长一起更新本网站!QQ:879621940

您当前所在位置:首页 »  .NET本质论第一卷:公共语言运行库教程 » 正文

本教程章节列表
最新评论

值类型的比较与排序

创建时间:2012年11月21日 21:07  阅读次数:(5366)
分享到:
由于同一性对于值类型通常没有意义,因此,值类型的Object.Equals的默认实现是对所有实例字段调用Object.Equals方法进行按成员比较,在许多情况下,CLR将灵活地优化这些调用,例如,当类型的所有字段都是基本数据类型时.CLR将作一个类型无关的内存比较。

示例5.6 实现System.Object.Equals
public sealed class Person(
string name;
double age;
public override bool Equals(Object rhs){
//总是等于自己
If(rhs==this) return true;
//其它对象的类型必须是Person
Person other=rhs as Person;
If(other==null) return false;
//比较name和age
Return other.name==name&&other.age==age;
}
Public override int GetHashCode(){
//这假定Person.name永不改变!
Return name.GetHashCode();
}

重写Object.Equals方法的类型必须同时重写Object.GetHashCode方法。程序可以使用Object.GetHasCode方法决定两个对象是否相等。如果两个对象返回不同的散列码,那么就可以保证它们是不相等的.如果两个对象返回相同的散列码,那么,它们可能相等也可能不相等。确认的惟一途径就是调用Object.Equals方法。Object.GetHashCode的实现通常比Object.Equals的开销要小得多,原因就是它不需要一个确定的答案。

如果不考虑编程语言的特殊性,则很难说清楚同一性和相等性。在C++ 和C#中,标准的比较操作符是==和!=。当这些操作符被应用在基本数据类型上时,它们只是简单地发射直接比较这两个值的CIL指令。当被应用在对象引用上时,这些操作符发射的CIL指争原则上等价于调用System.Object.ReferenceEquals方法。然而,c++和c#都支持操作符重载,这意味着一个特定的类型可能将==(和!=)操作符映射到任意代码。典型的例子就是System.String类型。System.String类型重载了这些操作符,使之调用Equals方法。于是,对于字符串比较,就能采用更为直观的相等比较。一般来说,重写Equals方法的类型应该考虑重载==和!=操作符,尤其当类型是(或者其行为像)值类型时。

GetHashCode和Equals实际上是为那些类似值类型的对象而设计的。它们的设计主要考虑那些底层值不变的对象(例如,System.String)。然而,当被应用到其相等性随时间而改变的对象上时,用于GetHashCode和Equals的约定存在着一些不一致性。一般来说,当没有不变的字段时(例如只读字段),实现GetHashCode是极其困难的。

对于类似值的类型,在该类型的实例上实施一个排序关系经常是很有用的。为了以统一的方式支持这种观点,CLR提供了一个标准的接口:SyStem.Comparable实现System.IComparable接口的类型,标明实例可被排序。如下所示,IComparable只有一个方法CompareTo:
namespace System{
 public interface IComparable{
   int CompareTo(Object rhs);
}

CompareTo方法返回一个int值,可能有三种结果。如果该对象的值小于指定参数值,CompareTo就返回一个负数;如果该对象的值大于指定参数值,CompareTo就返回一个正数;如果对象的值与指定的参数值相等,CompareTo就返回零。

IComparable接口与System.Object.Equals方法是相关联的。实现Icompable接口的类型必须提供Object.Equals的实现,这样才能与IComparable.CompareTo的实现保持一致。特别是下面例举的这些约束,总会应用到:
Using System;
Public class Utils{
Static void Test(IComparable o1,object o2){
//断言 CompareTo==0暗示了相等无性繁殖 
If(o1.CompareTo(obj2)==0)
Debug.Assert(o1.Equals(o2));

//断言相等就意味着CompareTo==0
If(o1.Equals(o2))
Debug.Assert(o1.CompareTo(o2)==0)’
}
}

同样,重写System.Object.Equals方法的类型也应该考虑实现IComparable接口。所有基本数据类型和System.String都是有序的,并且都实现了IComparable接口。你自己编写的类可以通过实现IComparable接口,使之能够产生排序。示倒5.7是一个实现了IComparable接口的类型,用于支持其实例的排序。

示例5.7实现System.IComparable接口
Public sealed class Person:System.IComparable{
Internal int age;
Public int CompareTo(object rhs){
If)(this==rhs) return 0;//
Person other=(Person)rhs;
If(other.age >this.age)
Return -1;
Else if(other.age<this.age)
Return 1;
Else
 return 0;
}
}

你可以在CompareTo方法中,对复台的if-else语句进行修改,如下所示:
Return this.age-other.age;
如果thls.age大于otner.age,该方法将返回一个正数,如果两个值相等,该方法返回零;否则,该方法返回一个负数。
来源:.net学习网
说明:所有来源为 .net学习网的文章均为原创,如有转载,请在转载处标注本页地址,谢谢!
【编辑:Wyf】

打赏

取消

感谢您的支持,我会做的更好!

扫码支持
扫码打赏,您说多少就多少

打开支付宝扫一扫,即可进行扫码打赏哦

最新评论

共有评论0条
  • 暂无任何评论,请留下您对本文章的看法,共同参入讨论!
发表评论:
留言人:
内  容:
请输入问题 8+14=? 的结果(结果是:22)
结  果: