思维的乐趣

Enjoy it
  博客园  :: 首页  :: 新随笔  :: 联系 :: 订阅 订阅  :: 管理

System.Object 类中的三个比较方法浅析

Posted on 2010-06-24 01:33  szh114  阅读(1228)  评论(0编辑  收藏  举报

在System.Object类中有三个被设计用来进行对象比较的方法:

public virtual bool Equals(Object obj);

public static bool Equals(Object objA,Object objB);

public static bool ReferenceEquals(Object objA,Object objB);

第一个是virtual 的,后两个是 static 的。ReferenceEquals() 实现了类型的引用比较,对该函数来讲,只有应用在引用类型上时才会有意义,比较两个值类型的引用将永远返回 false ,

 

无论它们的值是否相等。甚至下面的代码:

            int i = 0;

            Console.WriteLine(object.ReferenceEquals(i, i));

 

输出结果也是 false . 原因是:i 是值类型的int .在传入时被自动装箱为object型变量,并且装了两次,那就是两个不同的对象啦,因此引用不相等(原因是我猜测的,存疑!)

 

另一个静态的 Equals() 方法的功能根据不同的类型而有所不同。它的内部判断实际分了两步:首先检查两个对象是否恒等(对于值类型来说,就是检查值内容是否相等;对于引用类型来说,就是检查引用是否相等)。然后调用其中一个参数对象的实例的Equals方法来判断两个对象是否恒等。

利用反射可以看到 静态方法 Equals() 的代码:

 

public  static bool Equals(object objA,object objB)

{

  return  ((objA == objB || (((objA != null && objB != null && objA.Equals(objB)));

}

 

注意这里面只有一行代码,却是别有意味。它通过一个 || 运算符,把两种情况,值类型,跟引用类型,都包含了进去。一一分析:

如果objA , objB 皆为 值类型,则在 objA == objB 这一步骤无论如何都要得到一个false ,理由同前,因为它们要被装箱。实验如下:

            int ia = 5;
            int ib = 5;

 

            object oa = ia;    //这儿手动装下箱。
            object ob = ib;

            Console.WriteLine(oa == ob);                  // 结果是 false!!!

 

这时候后备的半句就用上了,

首先用 objA != null && objB != null 确保两个参数皆不为null ,然后调用了值类型本身的Equals 方法,这时候要明白,所有的值类型都继承自 System.ValueType 类,而ValueType 类复写了

public virtual bool Equals(Object obj);
方法,此时的Equals(Object obj)就可以进行值类型的恒等判断了,比较的是里面存放的内容,而非引用,这时候就能得到正确的结果了。验证如下:

            int ia = 5;
            int ib = 5;

 

            object oa = ia;
            object ob = ib;

            Console.WriteLine(oa == ob);               // 结果是 false!!!
            Console.WriteLine(oa.Equals(ob));         // 结果是 true !!!!!

前面我们假设的是两个值类型的情况,可以正常满足判断功能。当两个参数皆为引用类型的时候,objA == objB 这前半个条件已经够用了。当两个参数一个为值类型一个为引用类型,那就显然不用说,也会得到false 啦。。。

 

最后还有一个virtual 的 Equals(object obj) 方法,当我们需要构建自定义的比较时,就需要重写该方法,它的默认实现是大多情况下并不实用的引用比较,当然System.ValueType已经复写了该方法。所以系统定义的那些值类型可以放心使用,它们会正常比较值的内容的。

 

下面部分转自:在路上


重写Equals方法分为以下三种情况:

1.引用类型的基类没有重写Equals

2.引用类型的基类重写了Equals

3.值类型重写了Equals

通常写法是:

对象是否为空,为空返回false

对象类型是否相同,不同返回false

类型转换后进行引用与值的比较如下:

Object.Equals(v1,v2) ,不同返回false

v1.Equals(v2),不同返回false

 

对于基类,if(!base.Equals(v2)) return false;

 

值类型可以自己实现强类型的Equals,避免拆箱与装箱操作.注意System.ValueType.Equals()利用了反射实现,效率不高.

注意:Object.ReferenceEquals();

重写Equals必须重写GetHashCode()