《CLR via C#》对象的同一性和等一性,哈希码

对象的同一性和等一性

        开发人员经常需要比较对象。System.Object对象提供了名为Equals的虚方法。作用是对象包含两个相同值返回True。Object的Equals方法是向下面一样实现

public class Object
{
    public virtual Boolean Equals(Object obj)
    {
        //如果两个引用指向一个对象他们肯定相同
        if(this == obj) return true;
        //假定对象不包含相同的值
        return false;
    }
}

这样实质只实现了同一性而非等一性。Object的默认设置是不合理的。下面显示了Equals方法应该怎么正确的实现

1.如果obj实参为null返回false

2.如果obj和this引用同一个对象,返回true

3.如果obj和this引用不同类型返回false

4.针对类型定义的每个实例字段,将this字段中的值和obj字段进行比较,任何字节不相等返回false

5.调用基类的Equals方法来比较如果为false返回false

所以微软应该向下面这样实现Object的Equals方法

public class Object
{
    public virtual Boolean Equals(Object obj)
    {
        //比较对象不能为null
        if(obj == null) return false;
        //要属于相同类型
        if(this.GetType() != obj.GetType()) return false;
        //所有字段匹配的前提下返回True
        //由于Object没有任何字段,所以匹配
        return true;
    }
}

由于没有这样实现Equals,所以Equals的实现规则远远比想象的复杂。类型重写Equals时应该调用基类Equals实现。由于类型能重写Object的Equals方法,所以不能测试同一性。为了解决这个问题Object提供了静态方法ReferceEquals.

 public class Object
 {
     public static Boolean ReferenceEquals(Object a, Object b)
     {
         return (a == b);
     }
 }

检测同一性务必使用ReferceEquals,不应使用==操作符(除非现将两个操作数转换为object),因为某个操作数可能重载了==操作符,为其赋值不同于同一性的语意。

System.Value内部重写了Object的Equals方法。并进行了正确的实现来执行相等性检测。ValueType的Equals内部是这样实现的

1.如果obj为null返回false

2.如果this和obj实参引用不同类型对象就返回false

3.针对类型定义的每个实例字段,都将this对象的值与obs对象的值进行比对。任何字段不相等返回false

4.返回true。ValueType的Equals方法不调用Object的Equals方法。

在内部ValueType的Equals方法利用了反射完成了步骤3.由于CLR反射机制慢,定义自己的类型时应该重写Equals方法来提供实现,提高性能。当然不调用base.Equals

重写Equals要符合相对性的四个特征

1.Equals必须自反

2.Equals必须对称

3.Equals必须可传递

4.Equals必须一致

重写Equals时还需要做下面几件事

让类型实现System.IEqualable<T>接口的Equal方法

重载==和!=操作运算符方法,在内部调用类型安全的Equals

另外如果是排序类型的比较类型应该实现ICoparable的ComoareTO方法和IComparabel<T>类型安全的CompareTo方法。如果实现了这些方法可以考虑重载各种比较运算符(<,>,<=,>=),在这些方法内部调用类型安全的ComparaTo方法

对象哈希码

FCL设计者认为,如果能将任何对象的任何实例放到哈希表集合中,能带来很多好处。System.Object提供了虚方法GetHashCoe,它能获得任意对象 的Int32哈希码。如果你重写了Equals方法,还应该重写GetHashCode方法。这是因为在Dictionary,Hashtable以及一些集合的实现中。要求两个对象必须具有相同的HashCode才视为相等。所以,重写Equal就必须重写gethashCode以确保相等性算法和对象哈希码算法一致。

public sealed class Point
 {
     private readonly int x,y;
     public override int GetHashCode()
     {
         return x ^y;
     }
 }

 选择算法计算哈希码请遵守以下规则

1.这个算法提供良好分布

2.可以在算法中调用基类的GetHashCode方法,并包含返回值

3.算法至少使用一个实例字段

4.理想情况下字段应该不可变

5.算法执行速度尽快

6.包含相同值的不同对象返回相同哈希码。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值