C# 比较对象的相等性

eba12b4fb9c90784e16696ce8d6e1c48.png

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

01

223d7a71d5e85463b8e74857689822ba.png

比较引用类型的相等性

System.Object 定义了 3 个不同的方法来比较对象的相等性:ReferenceEquals()和两个版本的 Equals():一个是静态的方法,一个是可以重写的虚拟实例方法。还可以实现接口 IEquality<T>,它提供了一个具有泛型类型参数而不是对象的 Equals 方法。再加上比较运算符(==),实际上有4 种比较相等性的方法。这些方法有一些细微的区别,下面就介绍它们。

01  ReferenceEquals()方法

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

static void ReferenceEqualsSample()
{
   SomeClass x = new SomeClass(), y = new SomeClass(), z = x;
   
   bool bl = object.ReferenceEquals(null, null);  // returns true
   boo1 b2 = object.ReferenceEquals(null, x);     // returns false
   bool b3 = object.ReferenceEquals(x, y):        // returns false because x and y 
                                                  // references different objects
   bool b4 = object.ReferenceEquals(x, z);        // returns true because x and z 
                                                  // references the same object
   //...
}

02  Equals()虚方法

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

03  静态的 Equals()方法

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

04  比较运算符(==)

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

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

但是,如果把一些类看作值,其含义就会比较直观,这是可以接受的方法。在这些情况下,最好重写比较运算符,以执行值的比较。但一个明显例子是 System.String 类,Microsoft 重写了这个运算符,以比较字符串的内容,而不是比较它们的引用。

02

87e81c26d1498fa2889d348ddf1bf4f3.png

比较值类型的相等性

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

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

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

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

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

欢迎关注公众号: dotnet编程大全

技术群: 需要进技术群的添加小编微信mm1552923,备注:加群;

往期推荐

874d4ed40abb8021565e9a5a9255b70e.png

Love life,love yourself

关注小编不迷路呦~

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值