.Net(C#)中,对象的相等比较问题

简介:

以前一直没有关心这个问题,被别人问起,特记录一下. ( From csdn)

在讨论了运算符,并简要介绍了等于运算符后,就应考虑在处理类和结构的实例时相等意味着什么。理解对象相等比较的机制对编写逻辑表达式非常重要,另外,对实现运算符重载和数据类型转换也非常重要,本章的后面将讨论运算符重载。

对象相等比较的机制对于引用类型(类的实例)的比较和值类型(基本数据类型,结构或枚举的实例)的比较来说是不同的。下面分别介绍引用类型和值类型的相等比较。

5.3.1 引用类型的相等比较

System.Object的一个初看上去令人惊讶的方面是它定义了3个不同的方法,来比较对象的相等性:ReferenceEquals()和Equals()的两个版本。再加上比较运算符==,实际上有4种进行相等比较的方式。这些方法有一些微妙的区别,下面就介绍这些方法。

1. ReferenceEquals()方法

ReferenceEquals()是一个静态方法,测试两个引用是否指向类的同一个实例,即两个引用是否包含内存中的相同地址。作为静态方法,它不能重写,所以只能使用System.Object的实现代码。如果提供的两个引用指向同一个对象实例,ReferenceEquals()总是返回true,否则就返回false。但是它认为null等于null:

SomeClass x, y;

x = new SomeClass();

y = new SomeClass();

bool B1 = ReferenceEquals(null, null);                //return true

bool B2 = ReferenceEquals(null, x);                //return false

bool B3 = ReferenceEquals(x, y);                  //return false because x and y

                                            //point to different objects

2. 虚拟的Equals()方法

Equals()虚拟版本的System.Object实现代码也比较引用。但因为这个方法是虚拟的,所以可以在自己的类中重写它,按值来比较对象。特别是如果希望类的实例用作字典中的键,就需要重写这个方法,以比较值。否则,根据重写Object.GetHashCode()的方式,包含对象的字典类要么不工作,要么工作的效率非常低。在重写Equals()方法时要注意,重写的代码不会抛出异常。这是因为如果抛出异常,字典类就会出问题,一些在内部调用这个方法的.NET基类也可能出问题。

3. 静态的Equals()方法

Equals()的静态版本与其虚拟实例版本的作用相同,其区别是静态版本带有两个参数,并对它们进行相等比较。这个方法可以处理两个对象中有一个是null的情况,因此,如果一个对象可能是null,这个方法就可以抛出异常,提供了额外的保护。静态重载版本首先要检查它传送的引用是否为null。如果它们都是null,就返回true(因为null与null相等)。如果只有一个引用是null,就返回false。如果两个引用都指向某个对象,它就调用Equals()的虚拟实例版本。这表示在重写Equals()的实例版本时,其效果相当于也重写了静态版本。

4. 比较运算符==

最好将比较运算符看作是严格值比较和严格引用比较之间的中间选项。在大多数情况下,下面的代码:

bool b = (x == y);          //x, y object references

表示比较引用。但是,如果把一些类看作值,其含义就会比较直观。在这些情况下,最好重写比较运算符,以执行值的比较。后面将讨论运算符的重载,但显然它的一个例子是System.String类,Microsoft重写了这个运算符,比较字符串的内容,而不是它们的引用。

5.3.2 值类型的相等比较

在进行值类型的相等比较时,采用与引用类型相同的规则:ReferenceEquals()用于比较引用,Equals()用于比较值,比较运算符可以看作是一个中间项。但最大的区别是值类型需要装箱,才能把它们转换为引用,才能对它们执行方法。另外,Microsoft已经在System.ValueType类中重载了实例方法Equals(),以便对值类型进行合适的相等测试。如果调用sA.Equals(sB),其中sA和sB是某个结构的实例,则根据sA和sB是否在其所有的字段中包含相同的值,而返回true或false。另一方面,在默认情况下,不能对自己的结构重载==运算符。在表达式中使用(sA==sB)会导致一个编译错误,除非在代码中为结构提供了==的重载版本。

另外,ReferenceEquals()在应用于值类型时,总是返回false,因为为了调用这个方法,值类型需要装箱到对象中。即使使用下面的代码:

bool b = ReferenceEquals(v, v);          //v is a variable of some value type

也会返回false,因为在转换每个参数时,v都会被单独装箱,这意味着会得到不同的引用。调用ReferenceEquals()来比较值类型实际上没有什么意义。

尽管System.ValueType提供的Equals()默认重载肯定足以应付绝大多数自定义的结构,但仍可以为自己的结构重写它,以提高性能。另外,如果值类型包含作为字段的引用类型,就需要重写Equals(),以便为这些字段提供合适的语义,因为Equals()的默认重写版本仅比较它们的地址。



本文转自Jack Niu博客园博客,原文链接:http://www.cnblogs.com/skywind/archive/2007/04/06/702700.html,如需转载请自行联系原作者

相关文章
|
11月前
|
Java 物联网 C#
C#/.NET/.NET Core学习路线集合,学习不迷路!
C#/.NET/.NET Core学习路线集合,学习不迷路!
429 0
|
6月前
|
SQL 小程序 API
如何运用C#.NET技术快速开发一套掌上医院系统?
本方案基于C#.NET技术快速构建掌上医院系统,结合模块化开发理念与医院信息化需求。核心功能涵盖用户端的预约挂号、在线问诊、报告查询等,以及管理端的排班管理和数据统计。采用.NET Core Web API与uni-app实现前后端分离,支持跨平台小程序开发。数据库选用SQL Server 2012,并通过读写分离与索引优化提升性能。部署方案包括Windows Server与负载均衡设计,确保高可用性。同时针对API差异、数据库老化及高并发等问题制定应对措施,保障系统稳定运行。推荐使用Postman、Redgate等工具辅助开发,提升效率与质量。
215 0
|
10月前
|
开发框架 搜索推荐 算法
一个包含了 50+ C#/.NET编程技巧实战练习教程
一个包含了 50+ C#/.NET编程技巧实战练习教程
275 18
|
10月前
|
缓存 算法 安全
精选10款C#/.NET开发必备类库(含使用教程),工作效率提升利器!
精选10款C#/.NET开发必备类库(含使用教程),工作效率提升利器!
291 12
|
10月前
|
开发框架 人工智能 .NET
C#/.NET/.NET Core拾遗补漏合集(24年12月更新)
C#/.NET/.NET Core拾遗补漏合集(24年12月更新)
141 6
|
10月前
|
开发框架 算法 .NET
C#/.NET/.NET Core技术前沿周刊 | 第 15 期(2024年11.25-11.30)
C#/.NET/.NET Core技术前沿周刊 | 第 15 期(2024年11.25-11.30)
147 6
|
10月前
|
开发框架 Cloud Native .NET
C#/.NET/.NET Core技术前沿周刊 | 第 16 期(2024年12.01-12.08)
C#/.NET/.NET Core技术前沿周刊 | 第 16 期(2024年12.01-12.08)
143 6
|
10月前
|
程序员 C# 数据库
C# 比较对象新思路,利用反射技术打造更灵活的比较工具
中途接手的项目,碰到需要在更新对象信息时比较并记录差异的需求,最变态的还有附加要求,怎么办?有没有既能满足需求又能对项目影响最小的方法呢?分享这个我封装的方法,一个利用反射技术打造的更灵活的比较工具
144 5
|
10月前
|
开发框架 监控 .NET
C#进阶-ASP.NET WebForms调用ASMX的WebService接口
通过本文的介绍,希望您能深入理解并掌握ASP.NET WebForms中调用ASMX WebService接口的方法和技巧,并在实际项目中灵活运用这些技术,提高开发效率和应用性能。
594 5
|
10月前
|
算法 Java 测试技术
Benchmark.NET:让 C# 测试程序性能变得既酷又简单
Benchmark.NET是一款专为 .NET 平台设计的性能基准测试框架,它可以帮助你测量代码的执行时间、内存使用情况等性能指标。它就像是你代码的 "健身教练",帮助你找到瓶颈,优化性能,让你的应用跑得更快、更稳!希望这个小教程能让你在追求高性能的路上越走越远,享受编程带来的无限乐趣!
440 13