C#中的对象都继承自System.Object对象,分为引用类型和值类型两种,所以对象的相等比较而言就分两种,一种是比较引用,一种是比较值。System.Object默认提供了三个方法来进行对象的相等比较:静态的ReferenceEquals()、Equals()静态方法、Equals()虚方法(子类可以去重写)和“==”运算符。
1、静态的ReferenceEquals()
ReferenceEquals()是一个静态方法,比较两个对象是否引用自同一个地址,是则返回true,否则返回false
调用方法:ReferenceEquals(obj1,obj2)
比较原则:
ReferenceEquals()是一个静态方法,比较两个对象是否引用自同一个地址,是则返回true,否则返回false
调用方法:ReferenceEquals(obj1,obj2)
比较原则:
1)、obj1和obj2同为null,则返回true
2)、obj1和obj2只有一个为null,则返回false
3)、obj1和obj2均不为null时,比较两个对象的引用地址,是则返回true,不是则返回false
2)、obj1和obj2只有一个为null,则返回false
3)、obj1和obj2均不为null时,比较两个对象的引用地址,是则返回true,不是则返回false
2、 Equals()虚拟版本
System.Object实现代码也比较引用。但因为这个方法是虚拟的,所以可以在自己的类中重写它,按值来比较对象。特别是如果希望类的实例用作字典中的键,就需要重写这个方法,以比较值。否则,根据重写Object.GetHashCode()的方式,包含对象的字典类要么不工作,要么工作的效率非常低。在重写Equals()方法时要注意,重写的代码不会抛出异常。这是因为如果抛出异常,字典类就会出问题,一些在内部调用这个方法的.NET基类也可能出问题。
3、静态的Equals()方法
Equals()的静态版本与其虚拟实例版本的作用相同,其区别是静态版本带有两个参数,并对它们进行相等比较。这个方法可以处理两个对象中有一个是null的情况,因此,如果一个对象可能是null,这个方法就可以抛出异常,提供了额外的保护。静态重载版本首先要检查它传送的引用是否为null。如果它们都是null,就返回true(因为null与null相等)。如果只有一个引用是null,就返回false。
如果两个引用都指向某个对象,它就调用Equals()的虚拟实例版本。这表示在重写Equals()的实例版本时,其效果相当于也重写了静态版本。
4、“==”比较运算符
在默认情况下,==运算符对引用类型比较的是两个对象指向的引用是否是同一个对象,但是作为一个自定义的复杂类,可以自己重写适合自己的“==”运算符,在重写“==”时必须同时重写“!=”运算符。
在默认情况下,==运算符对引用类型比较的是两个对象指向的引用是否是同一个对象,但是作为一个自定义的复杂类,可以自己重写适合自己的“==”运算符,在重写“==”时必须同时重写“!=”运算符。
特殊注意的是:在重写相等比较时,要小心可能的循环调用问题
public
class
List
<T>
{
const
int
defaultCapacity = 4;
T[] items;
int
count;
public
int
Count
{
get
{
return
count; }
private
set
{ count =
value
; }
}
public
int
Capacity
{
get
{
return
items.Length;
}
set
{
if
(
value
< count)
value
= count;
if
(
value
!= items.Length)
{
T[] newItems =
new
T[
value
];
Array
.Copy(items, 0, newItems, 0, count);
items = newItems;
}
}
}
public
event
EventHandler
Changed;
public
List(
int
capacity=defaultCapacity)
{
this
.items=
new
T[capacity];
this
.Capacity = capacity;
this
.count = 0;
}
public
T
this
[
int
index]
{
get
{
return
items[index];
}
set
{
items[index] =
value
;
OnChanged();
}
}
public
void
Add(T item)
{
if
(count == Capacity) Capacity = count * 2;
items[count] = item;
count++;
OnChanged();
}
protected
virtual
void
OnChanged()
{
if
(Changed !=
null
) Changed(
this
,
EventArgs
.Empty);
}
public
override
bool
Equals(
object
other)
{
return
Equals(
this
, other
as
List
<T>);
}
public
override
int
GetHashCode()
{
return
this
.items.GetHashCode();
}
static
bool
Equals(
List
<T> a,
List
<T> b)
{
//不能用a==null或((object)a).Equals(null),会导致循环调用,因为它们会通过多态机制,最终调用实例的==或Equals(object other)
//可以用object.Equals(a,null)或(object)a==null,这会调用object的statice Equals(),这个静态比较方法内部有特殊处理,不进行多态机制的传递过程
if
(
object
.Equals(a,
null
))
return
object
.Equals(b,
null
);
if
(
object
.Equals(b,
null
) || a.count != b.count)
return
false
;
for
(
int
i = 0; i < a.count; i++)
{
//通过这个调用元素自身的Equals方法
if
(!
object
.Equals(a.items[i], b.items[i]))
{
return
false
;
}
}
return
true
;
}
public
static
bool
operator
==(
List
<T> a,
List
<T> b)
{
return
Equals(a, b);
}
public
static
bool
operator
!=(
List
<T> a,
List
<T> b)
{
return
!Equals(a, b);
}
}