细说对象的相等性

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

细说对象的相等性,布布扣,bubuko.com

时间: 2024-09-30 22:25:54

细说对象的相等性的相关文章

C#比較对象的相等性

对于相等的机制全部不同,这取决于比較的是引用类型还是值类型.以下分别介绍引用类型和值类型的相等性. 1.比較引用类型的相等性 System.Object定义了三种不同的方法,来比較对象的相等性:ReferenceEquals()和两个版本号的Equals().再加上比較运算符(==).实际上有4种进行比較相等的方式. 1.1 ReferenceEquals()方法 命名控件: System 程序集:mscorlib.dll 语法:public static bool ReferenceEqual

一起学习《C#高级编程》2--比较对象的相等性

今后争取每两天能更新一次.平日的诱惑太多,双休只顾玩了,进度有点慢. 接上一讲的,类型的安全性,留下了点小尾巴——比较对象的相等性. C#有四种比较相等的方式:除了“==”运算符外,System.Object定义了3中方法:ReferenceEqual()方法和两种Equals(): 1.首先是“==”运算符: 对于值类型,“==”比较两个值是否相等:而对于引用类型,“==”则是比较两个对象的引用地址是否相同.这里有个特例,就是string字符串类型,“==”是比较字符串的值而不是引用地址,这是

C#编程(三十九)----------比较对象的相等性

比较对象的相等性 需要理解对象相等的机制对逻辑表达式的编程很重要,另外,对实现运算符重载和类型强制转换也很重要. 对象相等的机制有所不同,这取决于比较的是引用类型还是值类型. 比较引用类型的相等性 System.Object定义了三个不同的方法来比较对象的相等性:ReferenceEquals()和Equals()两个版本,再加上比较运算符,实际上有四种进行相等比较的方式. 1.ReferenceEquals()方法 以下是ReferenceEquals()方法的定义 public static

c# 面相对象2-之封装性

c# 面相对象2-之封装性 一.封装特性: 这是一种隐藏的特性.可以用一个公式来展示类的封装特性: 封装的类=数据  +  对此数据进行的操作(即算法) 通俗的说,封装就是:包起外界不必要知道的东西,只向外界展露可供展示的东西. 在面向对象理论中,封装这个概念拥有更为宽广的含义.小到一个简单的数据结构,大到一个完成的软件子系统,静态的如某个软件系统要收集数据信息项,动态的如某个工作处理的流程,都可以封装到一个类中. 具备这种封装的意识,是掌握面向对象分析与设计技巧的关键 二.类的成员: 成员变量

c# 面相对象4-多态性

一.定义: 多态是面向对象程序设计的又一个特性.在面向过程的程序设计中,主要工作是编写一个个的过程或函数,这些过程和函数不能重名.例如在一个应用中,需要对数值型数据进行排序,还需要对字符型数据进行排序,虽然使用的排序方法相同,但要定义两个不同的过程(过程的名称也不同)来实现. 在面向对象程序设计中,可以利用“重名”来提高程序的抽象度和简洁性.首先我们来理解实际的现象,例如,“启动”是所有交通工具都具有的操作,但是不同的具体交通工具,其“启动”操作的具体实现是不同的,如汽车的启动是“发动机点火——

24.编写一个Car类,具有String类型的属性品牌,具有功能drive; 定义其子类Aodi和Benchi,具有属性:价格、型号;具有功能:变速; 定义主类E,在其main方法中分别创建Aodi和Benchi的对象并测试对象的特 性。

package zhongqiuzuoye; public class Car { String brand; public void drive() {} } package zhongqiuzuoye; public class Aodi extends Car{ public double price; public String model; public double speed; public Aodi(double price,String model,double speed)

读经典——《CLR via C#》(Jeffrey Richter著) 笔记_对象的相等性和同一性

[重写Equals注意的事项] 1. Equals 必须是自反的:--x.Equals(x)肯定为 true 2. Equals 必须是对称的:--x.Equals(y)肯定返回与y.Equals(x)相同的值 3. Equals 必须是可传递的:--x.Equals(y)返回true, y.Equals(z)返回true,则x.Equals(z)肯定返回true 4. Equals 必须是一致的.比较的两个值没有变,Equals返回的值(true或false)也不能变 5. 让类型实现 Sys

使用Linq中的Distinct方法对序列进行去重操作

使用Linq提供的扩展方法Distinct可以去除序列中的重复元素. 该方法具有以下两种重载形式: (1)public static IEnumerable<TSource> Distinct<TSource>(this IEnumerable<TSource> source) (重载1) 通过使用默认的相等比较器对值进行比较并返回序列中的非重复元素. (2)publicstatic IQueryable<TSource> Distinct<TSour

python之面相对象程序设计

一 面向对象的程序设计的由来 面向对象设计的由来见概述:http://www.cnblogs.com/linhaifeng/articles/6428835.html 面向对象的程序设计:路飞学院版 二 什么是面向对象的程序设计及为什么要有它 面向过程的程序设计:核心是过程二字,过程指的是解决问题的步骤,即先干什么再干什么......面向过程的设计就好比精心设计好一条流水线,是一种机械式的思维方式. 优点是:复杂度的问题流程化,进而简单化(一个复杂的问题,分成一个个小的步骤去实现,实现小的步骤将