class object
{
public virtual Boolean Equals(object obj)
{
//如果引用指向的是同一对象,肯定相等
if (this == obj) return true;
return false;
}
//......
}
该方法采取的策略可能是最简单的:如果进行比较的两个引用指向的是同一个对象,方法将返回true;否则在任何其他情况下,方法都将返回false。如果我们定义了自己的类型,且希望比较它们中的字段是否相等,则Object类型提供的默认实现对我们来说是不够的,必须重写Equals方法。
实现Equals方法有3种不同方式,我们逐一讨论。
-
为基类没有重写Object.Equals方法的引用类型实现Equals
class MyRefType : BaseType
{
//引用类型字段
RefType refobj;
//值类型字段
ValType valobj;
public override bool Equals(object obj)
{
//如果obj为null,不可能相等
if (obj == null) return false;
//如果两个对象类型不同,不可能相等
if (this.GetType() != obj.GetType()) return false;MyRefType other = (MyRefType)obj;
// 比较其中的引用类型字段
if ( ! object .Equals(refobj, other.refobj)) return false ;
// 比较其中的值类型字段
if ( ! valobj.Equals(other.valobj)) return false ;
return true ;
}
// 重载==和!=操作符
public static Boolean operator == (MyRefType o1, MyRefType o2)
{
return object .Equals(o1, o2);
}
public static Boolean operator != (MyRefType o1, MyRefType o2)
{
return ! (o1 == o2);
}
}
比较引用类型字段:
比较引用类型字段时,我们应该调用object的静态Equals方法,该方法是比较两个引用类型对象的辅助方法,以下代码展示了该方法的内部实现:public static Boolean Equals(Object objA, Object objB)
{
//如果objA与objB指向同一个对象,返回true
if (objA == objB) return true;
//如果objA或objB为null,不可能相等
if ((objA == null) || (objB == null)) return false;
//判断objA与objB是否相等
return objA.Equals(objB);
}
比较值类型字段,我们应该调用该字段类型的Equals方法来比较它们。不应该调用Object的静态Equals方法,因为值类型对象的值永远不可能为null,且调用object的静态Equals方法会对值类型对象执行装箱操作。 -
为基类重写了Object.Equals方法的引用类型实现Euqals
class MyRefType : BaseType
{
//引用类型字段
RefType refobj;
//值类型字段
ValType valobj;
public override bool Equals(object obj)
{
//首先让基类比较其中的字段
if (!base.Equals(obj)) return false;//以下代码与上一节中的实现相同
//如果obj为null,不可能相等
if (obj == null) return false;
//如果两个对象类型不同,不可能相等
if (this.GetType() != obj.GetType()) return false;MyRefType other = (MyRefType)obj;
//比较其中的引用类型字段
if (!object.Equals(refobj, other.refobj)) return false;
//比较其中的值类型字段
if (!valobj.Equals(other.valobj)) return false;
return true;
}
//重载==和!=操作符
public static Boolean operator ==(MyRefType o1, MyRefType o2)
{
return object.Equals(o1, o2);
}
public static Boolean operator !=(MyRefType o1, MyRefType o2)
{
return !(o1 == o2);
}}
注意:如果调用base.Equals会导致调用object.Equals方法,那就不应该调用它。 -
为值类型实现Equals方法
所有的值类型都继承自System.ValueType。ValueType重写了Object的Equals方法实现。ValueType.Equals方法在内部首先使用反射机制来得到类型所有的实例字段,然后再比较它们是否相等。这种方法效率很低,但却是一个所有值类型都能继承的默认实现。下面的代码展示了System.ValueType.Equals方法的内部实现:class ValueType
{
public override bool Equals(object obj)
{
if (obj == null) return false;
//得到this的类型
Type thisType = this.GetType();
if (thisType != obj.GetType()) return false;
//取得该类型的所有公有和私有实例字段
FieldInfo[] fields = thisType.GetFields(BindingFlags.Public | BindingFlags.NonPublic | BindingFlags.Instance);
for (int i = 0; i < fields.Length; i++)
{
//从两个对象中得到字段的值
object thisValue = fields[i].GetValue(this);
object thatValue = fields[i].GetValue(obj);
//如果字段值不等,返回false
if (!object.Equals(thisValue, thatValue)) return false;
}
return true;
}
//......
}struct MyValType
{
RefType refobj;
ValType valobj;
public override bool Equals(object obj)
{
if (!(obj is MyValType)) return false;
return this.Equals((MyValType)obj);
}
//强类型版本Equals
public Boolean Equals(MyValType obj)
{
if (!object.Equals(this.refobj, obj.refobj)) return false;
if (!this.valobj.Equals(obj.valobj)) return false;
return true;
}
//重载==操作符
public static Boolean operator ==(MyValType v1, MyValType v2)
{
return v1.Equals(v2);
}
public static Boolean operator !=(MyValType v1, MyValType v2)
{
return !(v1 == v2);
}
}
题外话:关于Object.ReferenceEquals静态方法
Equals方法的目的是比较两个类型实例是否相等,如两个实例有相同的状态或值,则返回true。然而,有时我们需要判断两个引用是否指向了同一个对象,为实现这个功能,Object提供了一个名为ReferenceEquals的静态方法,它的实现如下:
class object
{
public static Boolean ReferenceEquals(Object objA, Object objB)
{
return objA == objB;
}
}
ClassA obj1 = new ClassA();
ClassA obj2 = obj1;
Console.WriteLine(Object.ReferenceEquals(obj1, obj2));
ClassA obj2 = new ClassA();
Console.WriteLine(Object.ReferenceEquals(obj1, obj2));