1 从Object.Equals方法说起
使用Object.Equals方法能够确定两个Object实例是否相等。
Object.Equals方法具有下面重载形式:
(1)Object.Equals (Object)
该方法能够确定指定的Object是否等于当前的Object。相等时返回true,否则返回false。
(2)Object.Equals (Object, Object)
该方法能够确定指定的两个Object实例是否相等。相等时返回true,否则返回false。此方法为静态方法。
例1 定义Student类,并使用Object.Equals方法确定Student实例是否相等。
using System;
namespace IEquatableExp
{
public class Student
{
private int studentID;
private string studentName;
private int age;
public Student(int studentID, string studentName, int age)
{
this.studentID = studentID;
this.studentName = studentName;
this.age = age;
}
public int StudentID
{
get { return this.studentID;}
}
public string StudentName
{
get { return this.studentName; }
}
public int Age
{
get { return this.age; }
}
}
}
using System;
namespace IEquatableExp
{
class Program
{
static void Main(string[] args)
{
Student stu1 = new Student(1,"tiana",25);
Student stu2 = stu1;
Student stu3 = new Student(stu1.StudentID,stu1.StudentName,stu1.Age);
Console.WriteLine("(Student)stu1, (Student)stu2,(Student)stu3: ");
Console.WriteLine("stu1.Equals(stu2) = {0}", stu1.Equals(stu2));
Console.WriteLine("stu1.Equals(stu3) = {0}", stu1.Equals(stu3));
Console.WriteLine("Object.Equals(stu1, stu2) = {0}", Object.Equals(stu1, stu2));
Console.WriteLine("Object.Equals(stu1, stu3) = {0}", Object.Equals(stu1, stu3));
}
}
}
代码执行结果例如以下图所看到的:
从例1的执行结果能够了解到:
Object.Equals方法的默认实现仅支持引用相等。
2 说说引用相等和值相等
对于引用类型,Object.Equals方法会去推断对象的引用是否指向的是同一个对象,若指向的是同一个对象则觉得是引用相等。
如例1中的引用stu1与stu2指向同样的对象,而引用stu3指向了还有一个对象,所以调用Object.Equals方法确认stu1与stu2的相等性时会返回true,调用Object.Equals方法确认stu1与stu3的相等性时会返回false,虽然此时stu3指向的对象的值与stu1指向的对象的值同样。
对于值类型,Object.Equals方法是依据对象的值来确定对象的相等性的(MSDN上也称为按位相等)。此乃值相等也。
对于前面样例中的Student类,若改动其类型为struct,其它代码均不变,运行结果又会是如何的呢。
using System;
namespace IEquatableExp
{
//改动Student的类型为struct
public struct Student
{
//此部分代码不变
}
}
改动代码后再次运行程序,得到下面结果。
由于struct是值类型,所以通过Object.Equals方法确定struct对象是否相等是依据对象的值来推断的,非常显然样例中的stu1,stu2,stu3的值均同样,所以结果返回true。
3 C#中的值类型和引用类型
C#中,值类型包含:整型,长整型,浮点型,字符型,布尔型,枚举和结构体等。
引用类型包含:基类Object,字符串,用户自己定义的类,接口和数组等。
4 再来看一个使用Object.Equals方法的样例
以下通过例2来进一步说明Object.Equals方法的使用。
例2 代码中使用Object.Equals方法对整型,字符串,可变字符字符串是否相等进行推断。
using System;
using System.Text;
namespace IEquatableExp
{
class Program
{
static void Main(string[] args)
{
int a = 32;
int b = 32;
Console.WriteLine("(int)a = {0}; (int)b = {1}:", a, b);
Console.WriteLine("a.Equals(b) = {0}", a.Equals(b));
Console.WriteLine("Object.Equals(a, b) = {0}", Object.Equals(a, b));Console.WriteLine();
string str1 = "tiana";
string str2 = "tiana";
Console.WriteLine("(string)str1 = {0}; (string)str2 = {1}:", str1, str2);
Console.WriteLine("str1.Equals(str2) = {0}", str1.Equals(str2));
Console.WriteLine("Object.Equals(str1, str2) = {0}", Object.Equals(str1, str2));Console.WriteLine();
StringBuilder sb1 = new StringBuilder("tiana");
StringBuilder sb2 = new StringBuilder("tiana");
Console.WriteLine("(StringBuilder)sb1 = {0}; (StringBuilder)sb2 = {1}:", sb1, sb2);
Console.WriteLine("sb1.Equals(sb2) = {0}", sb1.Equals(sb2));
Console.WriteLine("Object.Equals(sb1, sb2) = {0}", Object.Equals(sb1, sb2));
}
}
}
代码运行结果例如以下图所看到的:
对于整型,我们无需做过多说明,由于当整型对象的值相等时即觉得对象相等。
对于字符串,虽然字符串是引用类型,可是字符串类String中已经对Object.Equals方法进行了重写,使字符串类支持值相等。
查看String类的源码,你会发现String类提供了下面几个Equals方法的重载。
当中Equals(Object):Boolean方法便是对Object.Equals方法的重写。
对于可变字符字符串类StringBuilder,我们相同通过查看其源码来分析结果产生的原因。
查看源码能够了解到,StringBuilder类仅提供了自己的Equals方法,而并没有重写Object.Equals方法,所以实例中“sb1.Equals(sb2)”会调用StringBuilder类自己实现的Equals方法,该方法被实现成支持值相等,而“Object.Equals(sb1, sb2)”部分仍然会调用Object.Equals方法的实现,依照引用来确认对象是否相等。正由于此,所以会出现样例中的结果。
通过分析例2的执行情况,我们能够学习到:
Object.Equals的默认实现仅支持引用相等,但派生类可重写此方法以支持值相等。
例2中的String类与StringBuilder类能够非常好的说明这点。
5 自娱自乐一下
以下给出一个非常小的样例,供大家自娱自乐一下。
例3 大家知道以下代码的运行结果吗?要是知道的话,请大声说出来吧。
using System;
namespace IEquatableExp
{
class Program
{
static void Main(string[] args)
{
int a = 32;
byte b = 32;
Console.WriteLine("(int)a = {0}; (byte)b = {1}:", a, b);
Console.WriteLine("a.Equals(b) = {0}", a.Equals(b));
Console.WriteLine("a.Equals(b) = {0}", b.Equals(a));
}
}
}
不知道的话,那就直接看以下的结果。
为什么会这样?大家自己去琢磨吧。
6 在Student类中重写Object.Equals方法
接下来,我们要再次改动我们的Student类,在类中重写Object.Equals方法使其支持值相等。
例4 使我们的Student类支持值相等
using System;
namespace IEquatableExp
{
public class Student
{
private int studentID;
private string studentName;
private int age;
public Student(int studentID, string studentName, int age)
{
this.studentID = studentID;
this.studentName = studentName;
this.age = age;
}
public int StudentID
{
get { return this.studentID;}
}
public string StudentName
{
get { return this.studentName; }
}
public int Age
{
get { return this.age; }
}public override bool Equals(Object otherObject)
{
if (otherObject == null)
{
return false;
}
Student otherStudent = otherObject as Student;
if (otherStudent == null)
{
return false;
}
else
{
return (this.StudentName == otherStudent.StudentName)
&& (this.StudentID == otherStudent.StudentID)
&& (this.Age == otherStudent.Age);
}
}public override int GetHashCode()
{
return this.StudentID.GetHashCode();
}
}
}
using System;
namespace IEquatableExp
{
class Program
{
static void Main(string[] args)
{
Student stu1 = new Student(1, "tiana", 25);
Student stu2 = stu1;
Student stu3 = new Student(stu1.StudentID, stu1.StudentName, stu1.Age);
Console.WriteLine("(Student)stu1, (Student)stu2, (Student)stu3: ");
Console.WriteLine("stu1.Equals(stu2) = {0}", stu1.Equals(stu2));
Console.WriteLine("stu1.Equals(stu3) = {0}", stu1.Equals(stu3));
Console.WriteLine("Object.Equals(stu1, stu2) = {0}", Object.Equals(stu1, stu2));
Console.WriteLine("Object.Equals(stu1, stu3) = {0}", Object.Equals(stu1, stu3));
}
}
}
执行程序,得到下面结果:
由于stu1,stu2,stu3的值相等,所以程序会返回true。
7 使我们的Student类实现IEquatable(T)接口
例5 实现IEquatable(T)接口
using System;
namespace IEquatableExp
{
public class Student:IEquatable<Student>
{
private int studentID;
private string studentName;
private int age;
public Student(int studentID, string studentName, int age)
{
this.studentID = studentID;
this.studentName = studentName;
this.age = age;
}
public int StudentID
{
get { return this.studentID;}
}
public string StudentName
{
get { return this.studentName; }
}
public int Age
{
get { return this.age; }
}public bool Equals(Student otherStudent)
{
if (otherStudent == null)
{
return false;
}
return (this.StudentName == otherStudent.StudentName)
&& (this.StudentID == otherStudent.StudentID)
&& (this.Age == otherStudent.Age);
}public override bool Equals(Object otherObject)
{
if (otherObject == null)
{
return false;
}
Student otherStudent = otherObject as Student;
if (otherStudent == null)
{
return false;
}
else
{
return Equals(otherStudent);
}
}public override int GetHashCode()
{
return this.StudentID.GetHashCode();
}
}
}
using System;
namespace IEquatableExp
{
class Program
{
static void Main(string[] args)
{
Student stu1 = new Student(1, "tiana", 25);
Student stu2 = stu1;
Student stu3 = new Student(stu1.StudentID, stu1.StudentName, stu1.Age);
Console.WriteLine("(Student)stu1, (Student)stu2,(Student)stu3: ");
Console.WriteLine("stu1.Equals(stu2) = {0}", stu1.Equals(stu2));
Console.WriteLine("stu1.Equals(stu3) = {0}", stu1.Equals(stu3));
Console.WriteLine("Object.Equals(stu1, stu2) = {0}", Object.Equals(stu1, stu2));
Console.WriteLine("Object.Equals(stu1, stu3) = {0}", Object.Equals(stu1, stu3));
}
}
}
代码执行结果例如以下图所看到的:
IEquatable(T)接口提供了Equals方法的定义,实现该接口的类须要提供Equals方法的实现,我们在Student类中实现了IEquatable(T)接口的Equals方法并重写了Object.Equals方法,使其均支持值相等。这样一来,能够使Object.Equals方法的行为与IEquatable<T>.Equals方法的行为保持一致。
至于程序的执行结果我就不做过多解释了,相信大家都能看得懂。
8 重载op_Equality和op_Inequality运算符
最后,在我们的Student类中,重载op_Equality和op_Inequality运算符
例6 此实例仅包括部分代码,以下所给代码是在例5的Student类中新增的代码
public static bool operator ==(Student student1, Student student2)同一时候给出測试代码。
{
if ((object)student1 == null || (object)student2 == null)
{
return Object.Equals(student1, student2);
}
return student1.Equals(student2);
}public static bool operator !=(Student student1, Student student2)
{
if ((object)student1 == null || (object)student2 == null)
{
return !Object.Equals(student1, student2);
}
return !student1.Equals(student2);
}
using System;
namespace IEquatableExp
{
class Program
{
static void Main(string[] args)
{
Student stu1 = new Student(1, "tiana", 25);
Student stu2 = stu1;
Student stu3 = new Student(stu1.StudentID, stu1.StudentName, stu1.Age);
Console.WriteLine("(Student)stu1, (Student)stu2,(Student)stu3: ");
Console.WriteLine("stu1 == stu2 = {0}", stu1 == stu2);
Console.WriteLine("stu1 != stu3 = {0}", stu1 != stu3);
}
}
}
执行结果例如以下图所看到的:
到这里,我们便能够确保全部測试相等性返回的结果均保持一致。
好了,就到这里了。
88