对象判等

基本概念:

  1. 值相等——表示比较的两个对象的数据成员按内存位分别相等,即两个对象类型相同,并且具有相等和相同的字段。
  2. 引用相等——表示两个引用指向同一对象实例,也就是同一内存地址。因此可以由引用相等推出其值相等,反之则不然。

object类中和判等相关的方法及其代码:

// Returns a boolean indicating if the passed in object obj is
// Equal to this.  Equality is defined as object equality for reference 
// types and bitwise equality for value types using a loader trick to 
// replace Equals with EqualsValue for value types).
// 
public virtual bool Equals(Object obj)
{
    return InternalEquals(this, obj);
}

[MethodImplAttribute(MethodImplOptions.InternalCall)]
internal static extern bool InternalEquals(Object objA, Object objB);

public static bool Equals(Object objA, Object objB)
{
    if (objA == objB)
    {
        return true;
    }
    if (objA == null || objB == null)
    {
        return false;
    }
    return objA.Equals(objB);
}

[ReliabilityContract(Consistency.WillNotCorruptState, Cer.Success)]
public static bool ReferenceEquals(Object objA, Object objB)
{
    return objA == objB;
}

一、public virtual bool Equals(Object obj) ,虚方法,比较对象实例是否相等。

    • 其行为和ReferenceEquals()一致,判断的是“引用相等”。但是值类型例外,System.ValueType重写了Object.Equals()方法,比较类型和内容。ValueType中的实现性能并不好,因为它是所有值类型的基类,为了提供正确的行为,它必须能够在不知道对象运行时类型的情况下,比较其派生类型中的所有成员变量,在C#中,这就意味着要使用反射。因此我们应该为自己的值类型提供一个更快的Equals()重写版本。
    • 对于引用类型,只有当我们希望更改其预定义语义时,才应该重写Equals()虚方法,例如:string。
    • 当我们重写Equals()虚方法时,如果基类的Equals()方法不是由System.Object或System.ValueType提供的话,我们也应该调用基类的Equals()方法。

二、public static bool Equals(Object objA, Object objB) ,静态方法,比较对象实例是否相等。

三、public static bool ReferenceEquals (Object objA, Object objB),静态方法,比较两个引用是否指向同一对象(.NET认为null等于null)。

    • 如果我们使用ReferenceEquals()来比较两个值类型,其结果永远返回false;即使我们将一个值类型和自身进行比较,返回值仍然是false。

四、“==”操作符在值类型情况下表示是否值相等,由值类型的根类System.ValueType提供了实现;而在引用类型情况下表示是否引用相等;“!=”相类似。

  • 只要我们创建值类型,都需要重新定义operator==()。其理由和重写ValueType.Equals()的理由一样。
  • 创建引用类型的时候,很少需要重写operator==()。因为它遵守“引用语义”。

下面是一个标准的Equals()虚方法的重写模式:

public override bool Equals(Object right)
{
    //检查是否为null
    //在C#方法中,this指针永远都不可能为null
    if (right == null)
        return false;
    //检查是否引用相等
    if (object.ReferenceEquals(this, right))
        return true;
    //检查类型
    if (this.GetType() != right.GetType())
        return false;
    return ComparerSampleMembers();
}

在检查类型的时候,也许有人会问说,类型兼容就可以了,为什么非要一致呢,于是就有了下面的实现:

//检查类型兼容性
Sample obj = right as Sample;
    if (obj == null)
        return false;
我们要牢记相等的数学属性:自反、对称、可传递。如果我们以上面的代码实现判等,则不满足对称性,很可能出现那种A==B,B!=A的情况,这是诡异,无法接受的。

posted on 2009-02-13 00:21  hzwang  阅读(364)  评论(0编辑  收藏  举报

导航