C#中对象的相等性与同一性的判断方法总结

C#对象的相等性与同一性

  • 1. 概述与准备
    • 1.1 概述
    • 1.2 准备
  • 2. Equals(Object)
    • 2.1 功能:
    • 2.2 实例:
    • 2.3 扩展:
    • 2.4 重写此方法
  • 3. Equals(Object, Object)
    • 3.1 功能
    • 3.2 实例
  • 4. ReferenceEquals(Object, Object)
    • 4.1 功能
    • 4.2 使用场景:
    • 4.3 要注意的地方
  • 5. 扩展:字符串的判等
    • 注意:
    • 如下:
  • 参考

在这里插入图片描述

1. 概述与准备

1.1 概述

在C#中,对象的相等性(equality)和同一性(identity)是两个不同的概念。

  • 相等性(Equality):相等性指的是两个对象的值是否相等。

    • 对于引用类型,默认情况下相等性比较的是对象的引用,即两个对象是否引用同一个内存地址;但可以通过重写 Equals 方法来自定义相等性比较的逻辑。
    • 对于值类型,相等性比较的是对象的值。
  • 同一性(Identity):同一性指的是两个对象是否是同一个实例。

    • 如果两个对象引用同一个内存地址,则它们是同一实例;
    • 否则,它们是不同的实例。

其实,这里涉及不少的值得关注的点,否则稍微不慎,便会出错。

这篇文章便总结一下**==操作符**、EqualReferenceEquals等等方法,以便更好地把握C#对象的相等性同一性

1.2 准备

为了方便后面举例子,这里先定义两个类:学生类学校类

class Student
{public int StuID { get; set; }public string StuName { get; set; }public School StuSchool { get; set; }public Student(int stuID, string stuName, School stuSchool){this.StuID = stuID;this.StuName = stuName;this.StuSchool = stuSchool;}
}class School
{public string SchoolName { get; set; }public string SchoolAddress { get; set; }public School(string name, string address){this.SchoolName = name;this.SchoolAddress = address;}
}

2. Equals(Object)

2.1 功能:

System.Object类型提供了名为Equals的虚方法,作用是判断指定对象是否等于当前对象。此方法比较的是对象的引用

public virtual bool Equals (object? obj);

2.2 实例:

Student stu1 = new Student(001, "孙悟空", new School("清华大学", "北京市"));
Student stu2 = new Student(002, "猪八戒", new School("北京大学", "北京市"));
Student stu3 = new Student(001, "孙悟空", new School("清华大学", "北京市")); //与stu1属性值相同//输出False。Equals方法比较的是对象的引用,而stu1和stu2是两个不同的对象,因此它们的引用不同。
Console.WriteLine(stu1.Equals(stu2)); //输出False。尽管stu1 和stu3的属性值相同,但它们仍然是两个不同的对象,因此它们的引用不同。
Console.WriteLine(stu1.Equals(stu3));

总结:对于Object的Equals方法的默认实现,它实现的实际是同一性(identity),而非相等性(equality)。这是易混淆的点!

2.3 扩展:

在 C# 中,== 操作符对于引用类型默认比较的是对象的引用,而不是属性值。stu1 和 stu2 是两个不同的对象,所以它们的引用不同,结果为 False。

Student stu1 = new Student(001, "孙悟空", new School("清华大学", "北京市"));
Student stu2 = new Student(002, "猪八戒", new School("北京大学", "北京市"));
Student stu3 = new Student(001, "孙悟空", new School("清华大学", "北京市")); //与stu1属性值相同Console.WriteLine(stu1 == stu2); //输出False
Console.WriteLine(stu1 == stu3); //输出False

2.4 重写此方法

上面讲到,此方法是一个虚方法,这意味着其派生类可以重写此类。如果你想的话,你可以在Student类中增加下面的代码,以至于实现相等性而非同一性,即能够按对象的属性值进行比较:

public override bool Equals(object? obj)
{if (obj == null && this.GetType() != obj.GetType())return false;Student other = (Student)obj;return this.StuID == other.StuID &&this.StuName == other.StuName &&this.StuSchool.Equals(other.StuSchool);
}
注意,上述代码中的 StuSchool 的判等取决于StuSchool.Equals()是否被重写。

3. Equals(Object, Object)

3.1 功能

这是Object类的静态方法,也是比较类对象的引用

public static bool Equals (object? objA, object? objB);

这里分几种情况:

  1. objA 与 objB 都为null,返回false;
  2. objA 与 objB 仅有一个为null,返回false;
  3. objA 与 objB 都不为null,调用objA.Equals(objB)并返回结果。

3.2 实例

Student stu1 = new Student(001, "孙悟空", new School("清华大学", "北京市"));
Student stu2 = new Student(002, "猪八戒", new School("北京大学", "北京市"));
Student stu3 = new Student(001, "孙悟空", new School("清华大学", "北京市")); //与stu1属性值相同Console.WriteLine(Object.Equals(stu1, stu2)); //输出False。这里实际上调用stu1.Equals(stu2);
Console.WriteLine(Object.Equals(stu1, stu3)); //输出False。这里实际上调用stu1.Equals(stu3);

4. ReferenceEquals(Object, Object)

4.1 功能

比较指定的 Object 实例是否是相同的实例,比较对象的引用。

public static bool ReferenceEquals (object? objA, object? objB);

注意:此方法不可重写

4.2 使用场景:

由于类型能够重写Equal方法,所以不能再用它测试同一性。为了解决这个问题,Object提供了另一个静态方法ReferenceEquals。

如果要测试两个对象引用是否相等,并且你不确定该类 Equals 方法是否被重写了,则可以调用此方法。

Student stu1 = new Student(001, "孙悟空", new School("清华大学", "北京市"));
Student stu2 = new Student(002, "猪八戒", new School("北京大学", "北京市"));
Student stu3 = new Student(001, "孙悟空", new School("清华大学", "北京市")); //与stu1属性值相同Console.WriteLine(Object.Equals(stu1, stu2));//输出False
Console.WriteLine(Object.ReferenceEquals(stu1, stu2)); //输出False

当你确定该类的Equals方法没有被重写,那这两个方法几乎是一样的。

4.3 要注意的地方

请注意,我为什么说“几乎是一样呢”?理由简单,因为有不一样的地方:

int a = 1;Console.WriteLine(a == a); //输出True。因为 == 操作符比较的是 int 类型的值。Console.WriteLine(a.Equals(a)); //输出True。因为在int类型中,Equals方法被重写成比较int类型的值。Console.WriteLine(Object.Equals(a, a)); //输出True。同上,这里会调用int类型的重写的Equals方法进行值的比较。Console.WriteLine(Object.ReferenceEquals(a, a)); //输出False。由于 a 是 int 类型的值类型,它在比较过程中会被装箱为一个对象。因此,两个 a 的引用是不同的,结果为 False。

总结:

  • 比较值类型时,如果 objA 并且 objB 是值类型,则会在将它们传递到 ReferenceEquals 方法之前进行装箱。这意味着,如果同时objA与objB表示值类型的同一实例,ReferenceEquals该方法仍返回false。
  • 检查引用类型对象的同一性时建议调用ReferenceEquals,不建议使用==或者Equals。

5. 扩展:字符串的判等

string s1 = "Hello";Console.WriteLine(s1 == s1); //输出TrueConsole.WriteLine(s1.Equals(s1)); //输出True。在string类型中Equals方法被重写,用于比较字符串的内容Console.WriteLine(Object.Equals(s1, s1)); //输出True。同上。Console.WriteLine(Object.ReferenceEquals(s1, s1)); //输出True。因为两个s1的引用是相同的。

注意:

  • 字符串常量会被存储在一个字符串池(string pool)中,以便重复使用。
  • 当创建两个具有相同内容的字符串时,它们实际上会引用相同的字符串对象。

如下:

string s2 = "Hello";Console.WriteLine(s1 == s2); //输出TrueConsole.WriteLine(s1.Equals(s2)); //输出True。在string类型中Equals方法被重写,用于比较字符串的内容Console.WriteLine(Object.Equals(s1, s2)); //输出True。同上。Console.WriteLine(Object.ReferenceEquals(s1, s2)); //输出True。由于值相同,所以s1与s2引用相同的字符串对象。

参考

https://learn.microsoft.com/zh-cn/dotnet/api/system.object?view=net-7.0

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/721992.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

数据结构学习(四)高级数据结构

高级数据结构 1. 概念 之所以称它们为高级的数据结构,是因为它们的实现要比那些常用的数据结构要复杂很多,能够让我们在处理复杂问题的过程中, 多拥有一把利器,同时掌握好它们的性质,以及所适应的场合,在…

《剑指offer》76--删除链表中重复的结点[C++]

目录 题目: 思路: 贴代码: 代码输出 题目: 在一个排序的链表中,存在重复的结点,请删除该链表中重复的结点,重复的结点不保留,最后返回链表头指针。 如: 链表1->…

PaddleOCR基于PPOCRv4的垂类场景模型微调——手写文字识别

PaddleOCR手写文字识别 一. 项目背景二. 环境配置三. 数据构造四. 模型微调五. 串联推理六. 注意事项七. 参考文献 光学字符识别(Optical Character Recognition, OCR),ORC是指对包含文本资料的图像文件进行分析识别处理,获取文字…

EXTJS实现自定义表格

宽度自适应 width: 100%, 高度自适应 height: 100% 同时设置表格所处页面高度100% html,body,#griddemo{height: 100%;} 自定义显示的文本内容 Ext.onReady(function () {Ext.QuickTips.init()function sexText(val) {if (val 0) {return <span style"color:green…

网络编程的学习

思维导图 多路复用代码练习 select完成TCP并发服务器 #include<myhead.h> #define SER_IP "192.168.125.73" //服务器IP #define SER_PORT 8888 //服务器端口号int main(int argc, const char *argv[]) {//1、创建用于监听的套接字int sfd -1;s…

QPainter::translate: Painter not active

画笔关联画布 就是这里少写了this指针

05_Mongooes

Mongooes Mongoose是通过Node来操作MongoDB的一个模块。是基于Node.js的第三方模块。 一、Node.js安装 1.解压 2.创建文件夹 解压路径下&#xff0c;创建两个文件夹 node_global&#xff1a;全局安装位置 node_cache&#xff1a;缓存 3.配置 配置环境变量 在path路径…

毫秒生成的时间戳如何转化成东八区具体时间

假设现在有一个时间是1709101071419L 后端代码实现 Java代码&#xff08;东八区时间&#xff09; 在Java代码中&#xff0c;我们将时区从UTC调整为东八区&#xff08;UTC8&#xff09;&#xff1a; import java.time.Instant; import java.time.ZoneId; import java.time.Z…

FreeRTOS操作系统学习——FreeRTOS工程介绍

FreeRTOS工程介绍 核心文件 FreeRTOS的最核心文件只有2个&#xff1a; FreeRTOS/Source/tasks.cFreeRTOS/Source/list.c 文件功能如下图&#xff1a; 头文件相关 内存管理文件 文件在 Middlewares\Third_Party\FreeRTOS\Source\portable\MemMang 下&#xff0c;它也是放…

JavaScript的`call`方法:实现函数间的调用!

&#x1f90d; 前端开发工程师、技术日更博主、已过CET6 &#x1f368; 阿珊和她的猫_CSDN博客专家、23年度博客之星前端领域TOP1 &#x1f560; 牛客高级专题作者、打造专栏《前端面试必备》 、《2024面试高频手撕题》 &#x1f35a; 蓝桥云课签约作者、上架课程《Vue.js 和 E…

堆和二叉树的动态实现(C语言实现)

✅✅✅✅✅✅✅✅✅✅✅✅✅✅✅✅ ✨✨✨✨✨✨✨✨✨✨✨✨✨✨✨✨ &#x1f33f;&#x1f33f;&#x1f33f;&#x1f33f;&#x1f33f;&#x1f33f;&#x1f33f;&#x1f33f;&#x1f33f;&#x1f33f;&#x1f33f;&#x1f33f;&#x1f33f;&#x1f33f;&#x1…

BUUCTF-Misc-[SUCTF 2019]Game1

题目链接&#xff1a;BUUCTF在线评测 (buuoj.cn) 下载附件一大堆文件&#xff0c;打开index.html时发现一大串base字符 U2FsdGVkX1zHjSBeYPtWQVSwXzcVFZLu6Qm0To/KeuHg8vKAxFrVQ 写代码和工具解都可以 填进去后错误&#xff0c;发现不是真的flag 查看另外一张照片&#xff0c;…

图像AI换脸软件:AI FaceSwap 中文版

AI FaceSwap 是一款利用人工智能技术进行面部交换的软件。该软件通过先进的人工智能算法&#xff0c;能够将一个人的面部表情、神态和特征准确地映射到另一个人身上&#xff0c;实现面部交换的效果。用户只需要提供两张照片&#xff0c;一张是目标人物的照片&#xff0c;另一张…

数据库进阶——如何提升数据库的安全性,以MySQL和Redis加固为例

目录 引出数据库加固加固思路MySQLRedis Redis冲冲冲——缓存三兄弟&#xff1a;缓存击穿、穿透、雪崩缓存击穿缓存穿透缓存雪崩 总结 引出 数据库进阶——如何提升数据库的安全性&#xff0c;以MySQL和Redis加固为例 数据库加固 加固思路 账号配置 应按照用户分配账号&…

Nginx使用—基础知识

Nginx简介 Nginx优点 高性能、高并发 支持很高的并发&#xff0c;在处理大量并发的情况下&#xff0c;比其他web服务器要高效 轻量且高扩展 功能模块少(源代码仅保留http与核心模块代码&#xff0c;其余不够核心代码会作为插件来安装) 代码模块化&#xff08;易读&#xff0…

C语言:qsort的使用方法

目录 1. qsort是什么&#xff1f; 2. 为什么要使用qsort 3. qsort的使用 3.1 qsort的返回值和参数 3.2 qsort的compare函数参数 3.3 int类型数组的qsort完整代码 4. qsort完整代码 1. qsort是什么&#xff1f; qsort中的q在英语中是quick&#xff0c;快速的意思了&#…

C++基础2:C++基本数据类型和控制结构

此专栏为移动机器人知识体系下的编程语言中的 C {\rm C} C从入门到深入的专栏&#xff0c;参考书籍&#xff1a;《深入浅出 C {\rm C} C》(马晓锐)和《从 C {\rm C} C到 C {\rm C} C精通面向对象编程》(曾凡锋等)。 2.C基本数据类型和控制结构 2.1 C基本数据类型 程序是由算法…

C# 中 Replace 字符串操作方法

在 C# 中&#xff0c;Replace 是一个字符串操作方法&#xff0c;用于替换字符串中的指定字符或子字符串。它接受两个参数&#xff1a;要查找和替换的字符串。Replace 方法在源字符串中查找所有匹配的字符或子字符串&#xff0c;并用指定的替换字符串进行替换。 下面是 Replace…

【论文精读】Mask R-CNN

摘要 基于Faster RCNN&#xff0c;做出如下改变&#xff1a; 添加了用于预测每个感兴趣区域(RoI)上的分割掩码分支&#xff0c;与用于分类和边界框回归的分支并行。mask分支是一个应用于每个RoI的FCN&#xff0c;以像素到像素的方式预测分割掩码&#xff0c;只增加了很小的计…

鸿蒙Harmony应用开发—ArkTS声明式开发(通用属性:点击回弹效果)

设置组件点击时回弹效果。 说明&#xff1a; 从API Version 10开始支持。后续版本如有新增内容&#xff0c;则采用上角标单独标记该内容的起始版本。 clickEffect clickEffect(value: ClickEffect | null) 设置当前组件点击回弹效果。 系统能力&#xff1a; SystemCapabilit…