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); //输出True

Console.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); //输出True

Console.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

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

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

突破编程_前端_JS编程实例(自适应表格列宽)

1 开发目标 针对如下的表格组件: 根据表格的各个列字符串宽度动态调整表格列宽: 2 详细需求 本组件目标是提供一个自动调整 HTML 表格列宽的解决方案,通过 JS 实现动态计算并调整表格每列的宽度,以使得表格能够自适应容器宽度&a…

Matlab|配电网智能软开关(sop)规划模型

目录 1 主要内容 目标函数 2 部分程序 3 程序结果 3.1 sop选址定容优化模型 3.2 对比算例(不含sop) 4 下载链接 1 主要内容 该程序参考文献《基于改进灵敏度分析的有源配电网智能软开关优化配置》,采用二阶锥算法,以改进的…

vscode 格式化prettier失败出现一大堆错误

如题,使用vscode开发项目时候,会自动进行格式化【安装prettier插件】 但是有时候会出现格式化失败的情况,如果插件安装正确,则可能是代码出现了格式问题。

使用腾讯云快速搭建WordPress网站流程详解

专栏系列文章: WordPress建站主题美化系列教程https://blog.csdn.net/seeker1994/category_12184577.html 一文搞懂WordPress是什么?为什么用它建站?怎么安装与部署? 初次安装WordPress后如何进行网站设置(主题安装、…

揭秘接口测试:完整流程指南!

在讲接口测试之前,首先需要给大家申明下:接口测试对于测试人员而言,非常非常重要,懂功能测试接口测试,就能在企业中拿到一份非常不错的薪资。 这么重要的接口测试,一般也是面试笔试必问。为方便大家更好的…

Python快速入门系列-2(Python基础语法)

第三章:Python基础语法 3.1 变量与数据类型3.1.1 变量的定义与赋值3.1.2 数据类型3.1.3 类型转换 3.2 注释与缩进3.2.1 注释3.2.2 缩进 3.3 条件语句与循环结构3.3.1 条件语句3.3.2 循环结构 3.4 函数与模块3.4.1 函数3.4.2 参数和返回值3.4.3 模块3.4.4 标准库中的…

基于SSH的点餐服务管理系统的设计与实现

目 录 摘 要 I Abstract II 引 言 1 1 开发工具相关技术 3 1.1 SSH框架 3 1.1.1 Spring 3 1.1.2 Spring MVC 3 1.1.3 Hibernate 4 1.2 前端技术 4 1.2.1 jQuery 5 1.2.2 Bootstrap 5 1.3 数据库技术 5 1.4 本章小结 6 2 系统分析 7 2.1 需求分析 7 2.2 系统工作流程 8 2.3 用例…

一学就会 | ChatGPT提示词极简指南-有爱AI实战教程(三)

演示站点: https://ai.uaai.cn 对话模块 官方论坛: www.jingyuai.com 京娱AI 导读:在使用 ChatGPT 时,当你给的指令越精确,它的回答会越到位,举例来说,假如你要请它帮忙写文案,如…

【Claude 3】一文谈谈Anthropic(Claude) 亚马逊云科技(Bedrock)的因缘际会

文章目录 前言1. Anthropic的诞生2. Anthropic的“代表作”——Claude 3的“三驾马车”3. 亚马逊云科技介绍4. 强大的全托管服务平台——Amazon Bedrock5. 亚马逊云科技(AWS)和Anthropic的联系6. Claude 3模型与Bedrock托管平台的关系7. Clude 3限时体验入口分享【⚠️截止3月1…

【Flink】Apache Flink 常见问题定位指南

Apache Flink 常见问题定位指南 1.问题分析概览1.1 如何分析 Flink 问题 2.常见问题处理2.1 作业自动停止2.2 输出量稳定但不及预期2.3 输出量逐步减少或完全无输出2.4 个别数据缺失2.5 作业频繁重启 3.问题追因技巧3.1 常用工具3.1.1 内存3.1.2 CPU3.1.3 磁盘 I/O3.1.4 网络 I…

187基于matlab的弹道目标跟踪滤波方法

基于matlab的弹道目标跟踪滤波方法,扩展卡尔曼滤波(extended Kalman filter, EKF)、转换测量卡尔曼滤波(conversion measurement Kalman filter, CMKF)跟踪滤波,得到距离、方位角、俯仰角误差结果。程序已调…

qt一个项目只能有一个QMainWindow,其他小窗口只能继承QWidget

我继承QMainWindow,结果就出现奇奇怪怪的现象,我人都疯了 这些接口全他妈不能用 删了换成QWidget就可以用了

ROS2中launch编写及参数含义(xml、python)

ROS2系列文章目录 ROS2中nav_msgs/msg/Path 数据含义及使用 ROS2中std_msgs/msg/Header 数据含义及使用 ROS中TF变换详解 文章目录 ROS2系列文章目录ROS2中launch编写及参数含义(xml、python)一、ROS官方介绍二、实现案例1.编写主函数、CMakeLists.tx…

qt的layoutStretch,非常重要

在几个控件横着布局中,不要指望着这些限制大小的接口能帮你什么 a->setMaximumWidth(); a->setMinimumWidth();我这里有两个控件,设置layoutStretch 1,1

poll开发服务器

int poll(struct pollfd *fds, nfds_t nfds, int timeout); 函数说明:与select类似,委托内核监控可读,可写,异常事件。 函数说明: fds:一个struct pollfd结构体数组的首地址 struct pollfd { …

上门废品回收小程序开发,互联网回收创业模式,稳占回收市场

随着人们生活水平的提高,我国居民产生了大量的废弃物品,这为废品回收行业提供了巨大的市场空间。 当下,废品回收行业成为了不少年轻人讨论的热门话题,吸引了越来越多的企业商家进行到市场中,成为了一个创业的重要行业…

【附教程】2024,人工智能+AI绘画,看这里就够了~14款主流图像生成软件工具总有一个适合你

AI绘画技术通过深度学习和处理海量图像数据,能够迅速将文字描述转化为富有创意和艺术性的画作。这一技术不仅极大地提升了艺术家的创作效率和作品质量,还为他们提供了全新的灵感来源和创作方式,推动了艺术领域的创新与发展。 同时&#xff0…

项目管理【引论一】项目管理的目标和高层次目标

系列文章目录 【引论一】项目管理的目标和高层次目标 一、项目管理的目标 项目管理的目标是在规定的时间内,在批准的预算内,完成事先确定的工作范围内的工作,并且达到预期的质量性能要求。 1.时间、成本和质量之间的关系 1.1时间、成本和…

(C语言)二分查找 超详细

📌 博客主页 爆打维c 目录 一、二分查找的原理 1.优点 2.缺陷 3.原理(核心思想) 4.例题 描述 思路: 一、二分查找的原理 在讲原理之前,先为大家分析一下二分查找的优缺点。 1.优点 如果我们要在数组里面找一个元素的位置…

ElasticSearch 底层读写原理

ElasticSearch 底层读写原理 ​ 写请求是写入 primary shard,然后同步给所有的 replica shard;读请求可以从 primary shard 或 replica shard 读取,采用的是随机轮询算法。 1、ES写入数据的过程 1.选择任意一个DataNode发送请求&#xff0c…