当前位置:编程学习 > C#/ASP.NET >>

重载Object的虚方法——重载Equals和运算符

Object是所有类的顶级父类,而Object又提供了四个虚方法:

Equals , GetHashCode, ToString, Finalize。

那么在这个系列文章中,我们就看下,我们对这四个方法的利用。

首先是引用类型重载Equals,我分成三步:

1. 空值验证

2. 类型验证

3. 比较验证

代码如下:

class Person
{
    public string Name { get; set; }
    public int Age { get; set; }
    public City MyCity { get; set; }
    public override bool Equals(object obj)
    {
        if (obj == null) 
        { 
            return false; 
        }
        if (obj.GetType() != this.GetType()) 
        { 
            return false; 
        }
        Person personTemp = obj as Person;
        if (!Object.Equals(this.MyCity, personTemp.MyCity))
        {
            return false;
        }
        if (this.Age != personTemp.Age || this.Name != personTemp.Name)
        {
            return false;
        }
        return true;
    }
}

 

在此需要注意的是,在比较引用类型属性的值是,需要使用Object的静态方法去比较,主要是为了防止属性值为null而抛出异常。我们来看下Object的静态Equals实现就明白了:

public static bool Equals(object objA, object objB)
{
    return ((objA == objB) || (((objA != null) && (objB != null)) && objA.Equals(objB)));
}

 

呵呵,很漂亮的实现。解释一下,其实就是首先比较两者是否指向同一块引用,然后判断两者是否都不为空,最后来调用类型的Equals重载方法。

接下来,我们看下,如果这个时候我们实现了一个Person类的子类,我们该怎么写?

class Programmer:Person
{
    public int CodeRowCount { get; set; }
    public override bool Equals(object obj)
    {
        if (!base.Equals(obj)) { return false; }
        Programmer pTemp = (Programmer)obj;
        if (pTemp.CodeRowCount != this.CodeRowCount) { return false; }
        return true;
    }
}

 

来简单解释一下,由于Person已经判断了obj是否为空啊,类型是否相等,基类的字段是否相等,因此我们不需要再操心了,我们只需要比较子类独有的字段是否相等即可。

这里我们强调下,在Object默认的Equals实现中,比较的是两个对象是否指向了同一个引用,因此,如果我们的父类没有重载Equals方法,那么我们的这个版本将永远都是错误的,因此,我们也可以看出实现Equals方法的重要性吧,呵呵!

最后是值类型(主要是结构体)的重载Equals的方法,首先让我们看看所有值类型的父类System.ValueType对于Equals的实现:

public override bool Equals(object obj)
{
    if (obj == null)
    {
        return false;
    }
    RuntimeType type = (RuntimeType)base.GetType();
    RuntimeType type2 = (RuntimeType)obj.GetType();
    if (type2 != type)
    {
        return false;
    }
    object a = this;
    if (CanCompareBits(this))
    {
        return FastEqualsCheck(a, obj);
    }
    FieldInfo[] fields = type.GetFields(BindingFlags.NonPublic | BindingFlags.Public | BindingFlags.Instance);
    for (int i = 0; i < fields.Length; i++)
    {
        object obj3 = ((RtFieldInfo)fields[i]).InternalGetValue(a, false);
        object obj4 = ((RtFieldInfo)fields[i]).InternalGetValue(obj, false);
        if (obj3 == null)
        {
            if (obj4 != null)
            {
                return false;
            }
        }
        else if (!obj3.Equals(obj4))
        {
            return false;
        }
    }
    return true;
}

 

方法很长,我来解释一下:

首先,依然是来判断obj是否为空;

接下来,来得到两个对象的类型,在这里出现了一个类是RuntimeType,我们Reflector下这个类:

image

是一个Internal类型,程序集外无法访问,但是我们通过名称和其中的属性和方法名大概可以猜出,这是一个用于针对运行时反射而专门设计的类型。

接下来出现了CanCompareBits,FastEqualsCheck这两个方法,在Reflector中无法看到实现,但是根据方法名,我猜想应该是判断这个对象是否可以按位比较(我不是很理解,是指的序列化么?),如果可以的话,直

补充:软件开发 , C# ,
CopyRight © 2012 站长网 编程知识问答 www.zzzyk.com All Rights Reserved
部份技术文章来自网络,