浅谈.Net中的对象相等

发表于:2011-7-13 10:23

字体: | 上一篇 | 下一篇 | 我要投稿

 作者:小城故事    来源:51Testing软件测试网采编

#
DotNet

  .Net中对象相等比较,是看似简单,实际上有点儿复杂。这和现实世界的情况差不多,无论人或物,现实中没有两个绝对相等,只有相对的属性一致或同属某个类别,这学问细究下去无穷无尽,一辈子也未必参得透。而.Net中的相等,没有那么捉摸不透,却也值得品味一番。

  说到相等,新手上来,先学到的就是相等操作符==(有的.Net语言中是单=),这个很自然,问题是有不少人工作了一两年,提到相等还是只想到操作符,就太片面了。

  在这里,茴香豆的茴字有四种写法,.Net中也主要有四种相等比较,分别是:==操作符、Object.Equals方法、Object.ReferenceEquals方法、对象实例的Equals方法。

  先来看Object的两个静态方法,它们逻辑比较简单。ReferenceEquals方法是比较两个对象的引用是否相同,即栈上的地址是否一样,对于值类型没有意义,参数中若有值类型参数出现,必定返回false。它主要用来测试,实际应用开发中很少用到,方法名也有点长。对于引用类型,如果方法结果为True,这个相等是最严格、最纯粹、如假包换的相等,说明这两个参数其实是同一个对象,当然无论用其他哪种相等比较方式,同样也应返回True。

  Object的Equals静态方法实际上是对实例Equals方法的扩展,增加了null的判断,适应于比较两个可能为空引用的对象。对于值类型,和Equals实例方法功能完全一样。

  再来看==,我们天天打交道的这小小操作符并不那么简单。上面,我们说两个Object静态方法区别在值类型和引用类型上,对于其他相等比较区别也主要在此。一般情况下,不是所有,对于引用类型==和ReferenceEquals静态方法作用相同;值类型在这里则有区分,对于原生值类型,如int,double,long,char等,==是直接比较其数值,而且不同类型间可以互相比较,比如int和char,'A’==65返回的是True;而对于一般的Struct,如果没有在代码中定义==(也包括!=)操作符,是不能用==比较的。

  引用类型也可以定义==操作符,覆盖CLR原生支持的比较。最常见的是String类型,它就定义了==操作符,很合理地放宽了相等的条件,使得String类型像原生值类型一样按值比较。String类的==操作符其实就是直接调用的被自己重写过Equals方法。

  String类是最常用也最特别的一个类,大部分面试都会问到String的特点,除了不可变和内存驻留机制外,其他主要特点就是相等的特殊性了。

  最后就来说说实例Equals方法吧,这是个Virtual方法,是我们在应用开发中,经常要根据业务逻辑需要,进行覆写的方法。定义并使用操作符固然方便,不过除了像String之类的特殊情况,引用类型让==保持默认规则是更好的选择,而让Equals方法实现业务上的“值”相等。如果不覆写,Equals方法也是比较对象的引用。

  对于值类型,实现==操作像一个点缀,而如果想实现相等比较操作,应该优先重写Equals方法(同样若要实现大小比较,应该优先实现IComparable接口,而不是实现比较操作符),从Object继承的Equals方法用于值类型时,比较两个对象的所有字段,全相等才为True。要注意它据说用了反射,效率很低的。但是它低归低,为什么一定要优先重写它?

  因为所有.Net Framework键值集合,都是用Equals实例方法做比较的,所以它实际上成了.Net中的法定天平,无论是原生类型、结构或类的实例,都应以Equals方法作为其标准的相等比较方式,包括我们自己实现的类型。用实例方法的好处也可以理解,更灵活,我们可以添加一些重载的Equals方法,申明不同的比较前提条件。与重写的默认Equals方法配合,构成一套完整的比较规则,以符合现实里复杂多变的标准。

  重写Equals方法时,官方推荐重写GetHashCode方法,要是你不用此类型作键值集合键的话,其实无所谓。

  个别情况中,复杂到重载Equals方法也力不从心时,我们就要定义专门用来比较相等的功能类。.Net Framework已经提供了一个接口System.Collections.IEqualityComparer,并有几个内置的实现,如StringComparer、EqualityComparer,我们自己写的比较类也不妨实现这个接口,当然,只要能用也不必计较那么多。看.Net Framework源代码,能发现好多个乱七八糟的类用于比较相等,大概是内部特权吧。

  结尾外,总结一张表,可以一目了然:

  注:为了排版,图好像不是很清楚,大家可以点击查看大图。

  通过本文的介绍,希望对你有帮助。

《2023软件测试行业现状调查报告》独家发布~

关注51Testing

联系我们

快捷面板 站点地图 联系我们 广告服务 关于我们 站长统计 发展历程

法律顾问:上海兰迪律师事务所 项棋律师
版权所有 上海博为峰软件技术股份有限公司 Copyright©51testing.com 2003-2024
投诉及意见反馈:webmaster@51testing.com; 业务联系:service@51testing.com 021-64471599-8017

沪ICP备05003035号

沪公网安备 31010102002173号