浅谈.Net中的对象相等

开发 后端
本文主要介绍的是.NET中的对象相等,也许很多人会把对象相等和对象一致弄混了。相信你看了本文就会明白的,希望对你有帮助,一起来看。

.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源代码,能发现好多个乱七八糟的类用于比较相等,大概是内部特权吧。

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

比较数据表

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

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

【编辑推荐】

  1. 大型高性能ASP.NET系统架构设计
  2. ASP.NET配置文件Web.config详细解释
  3. .NET三层架构解析一:什么是三层架构
  4. ASP.NET控件10个最有用的属性详解
  5. 回顾.NET Remoting分布式开发
责任编辑:于铁 来源: XiaoMing的点滴
相关推荐

2009-04-28 10:08:28

ADO.NET对象微软

2011-08-23 10:58:59

2009-06-29 10:50:18

VB.NET面向对象能力

2009-07-27 13:01:28

TreeViewASP.NET

2009-06-26 10:48:45

职责链模式.NET

2009-06-10 22:06:29

JavaScript面向对象

2009-05-08 09:46:37

微软C#集合对象

2009-01-16 13:17:16

AjaxASP.NET.NET

2009-07-22 17:07:16

WPF插件开发.NET Framew

2009-05-26 09:09:50

.NET FramewStream.Read基础类

2011-06-08 11:36:16

ASP.NETrender

2009-07-21 08:21:46

Scala对象相等性

2009-07-30 12:35:51

ASP.NET中的对象

2009-08-03 15:06:43

C# Stack对象C# Queue对象

2009-06-09 11:37:51

ViewStateViewDataASP.NET

2009-04-21 09:37:50

ASP.NETAjaxJavaScript

2010-05-20 08:50:45

UrlRoutingASP.NET 4.0

2009-12-21 10:05:10

ASP.NET MVC

2009-07-07 10:44:14

多态

2009-06-23 11:49:22

跨进程消息钩子VB.NET
点赞
收藏

51CTO技术栈公众号