比较对象相等性的四种方法
System.Object定义了3个不同的方法,来比较对象的相等性:ReferenceEquals()和两个版本的Equals()。再加上比较运算符(==),实际上是有四种比较相等的方式。
在编程中实际上我们只需要这两种比较,c#中类型也就这两种
(1)值类型的比较:一般我们就是判断两个值类型实例的各自包含的值是否相等
(2)引用类型的比较:由于引用类型在内存中的分布有两部分,一个是引用类型的引用(存在于线程栈中),一个是引用类型的值(存在于托管堆);所以我们比较引用类型也就存在两种比较
默认情况下:值类型比较的是两个值是否相等(不装箱情况下),引用类型比较的是两个引用是否相等。
1.ReferenceEquals()
ReferenceEquals()是一个静态方法,测试两个引用是否引用类的同一个实例。特别是两个引用是否包含内存中的相同地址。作为静态方法,他不能重写,所以system.Object的实现代码保持不变。
2.虚方法Equals()
Equals()虚拟版本的System.Object实现代码也可以用于比较引用。但因为这个方法是虚方法,所以可以在自己的类中重写他,从而按值来比较对象。
注意:对于Object对象比较的是引用!然而对于值类型,类型相同(不会进行类型自动转换),并且数值相同(对于struct的每个成员都必须相同),则Equals返回 true,否则返回false。这是为什么呢? 这是因为内置的值类型都重写了Object.Equals方法,所以值类型的Equals方法与引用类型的Equals就产生了不同的效果。
Equals在程序运行时决定比较的类型--根据对象的实际类型进行比较,根据对象的类型调用他们各自的Equals虚方法。
3.静态的Equals()方法
Equals()的静态版本与虚拟实例版本的作用相同,其区别是静态版本带有两个参数,并对他们进行相等性的比较。
用反编译工具反编译System.dll得到方法的实现源码:
public static bool Equals(object objA, object objB)
{
if (objA == objB)
{ return true; }
if ((objA != null) && (objB != null))
{ return objA.Equals(objB); }
return false;
}
4.比较运算符(==)
定义:静态相等符号,对应存在的!=,这个符号是一个可以重载的二元操作符,可以用于比较两个对象是否相等。使用==比较对象时,C#在编译时就决定了所比较的类型,而且不会执行任何虚方法(Object.Equals)。这是大家所期望的相等行比较。
- 对于内置值类型,==判断的是两个对象的代数值是否相等。它会根据需要自动进行必要的类型转换,并根据两个对象的值是否相等返回true或者false
- 对于引用类型,则==一般情况下比较的这是引用类型的引用是否相等。
注意:但是某些内置的引用类型重载了==符号,例如string就重载==,使其比较的不是两个字符串的引用,而是比较的两个字符串字面量是否相等,所以对于引用类型最好不要使用==符号进行相等性比较,避免混淆。
【对于引用类型利用==除了string是比较其值外,其余都是比较其引用,因为string是经常需要操作,所以会直接比较其值,所以会对其特殊对待,所以如果遇见特殊的引用类型需要查看一下是否进行了==重载,默认情况大家都可以把==在比较引用类型时当成比较引用!】
下面是关于四种比较的例子:
class Program
{
static void Main(string[] args)
{
string personName1 = "张三";
string personName2 = "李四";
int age1 = 22;
int age2 = 22;
Student Person1, Person2;
Person1 = new Student(personName1);
Person2 = new Student(personName2);
//1.实例Equals() 虚方法,比较引用,可重写来比较值
bool b1 = personName1.Equals(personName2);
bool b2 = age1.Equals(age2);
bool b3 = Person1.Equals(Person2);
Console.WriteLine("1.实例Equals()结果:");
Console.WriteLine("personName1.Equals(personName2) :{0}", b1);
Console.WriteLine("age1.Equals(age2) :{0}", b2);
Console.WriteLine("Person1.Equals(Person2) :{0}", b3);
Console.WriteLine("------------------------------------------------");
//2.==
bool b4 = personName1 == personName2;
bool b5 = age1 == age2;
bool b6 = Person1 == Person2;
Console.WriteLine("2.==:");
Console.WriteLine("personName1 == personName2 :{0}", b4);
Console.WriteLine("age1 == age2 :{0}", b5);
Console.WriteLine("Person1 == Person2 :{0}", b6);
Console.WriteLine("------------------------------------------------");
//3.ReferenceEquals()
bool b7 = ReferenceEquals(personName1, personName2);
bool b8 = ReferenceEquals(age1, age2);
bool b9 = ReferenceEquals(Person1, Person2);
Console.WriteLine("3.ReferenceEquals():");
Console.WriteLine("ReferenceEquals(personName1,personName2) :{0}", b7);
Console.WriteLine("ReferenceEquals(age1,age2) :{0}", b8);
Console.WriteLine("ReferenceEquals(Person1,Person2) :{0}", b9);
Console.WriteLine("------------------------------------------------");
//4.静态的Equals()
bool b10 = Equals(personName1, personName2);
bool b11 = Equals(age1, age2);
bool b12 = Equals(Person1, Person2);
Console.WriteLine("3.Equals():");
Console.WriteLine("Equals(personName1,personName2) :{0}", b10);
Console.WriteLine("Equals(age1,age2) :{0}", b11);
Console.WriteLine("Equals(Person1,Person2) :{0}", b12);
Console.WriteLine("------------------------------------------------");
int i = 5;
float j = 5;
bool bb = i.Equals(j);//不会进行类型转换
bool bb1 = i == j;
bool bb2 = Equals(i, j);
Console.WriteLine("i.Equals(j):{0}", bb);
Console.WriteLine("i==j:{0}", bb1);
Console.WriteLine("Equals(i,j):{0}", bb2);
Console.WriteLine();
Console.ReadKey();
}
}
public class Student
{
private string name;
public Student(string name)
{
this.name = name;
}
public void ShowName()
{
Console.WriteLine(this.name);
}
}
运行结果如下:

|