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

news2025/6/15 4:35:23

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

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

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

相关文章

成人商务英语,外贸英语纺织英语日常交流口语柯桥学外语

大家好,今天我们要说的这个短语,跟香蕉Banana有关,它就是top banana。 不过它可不是字面上的“顶级香蕉”的意思哦~ Top banana是一个俚语,常见的意思有两个: 1. the most important person in any group 一群人中最…

第14章 西瓜书——概率图模型

概率图模型 概率图模型(Probabilistic Graphical Model)是用图结构来表示多元随机变量之间条件依赖关系的模型。在图模型中,节点表示随机变量,边表示变量之间的依赖关系。概率图模型可以分为有向图模型(如贝叶斯网络&a…

C#与欧姆龙PLC实现CIP通讯

参考文档: 欧姆龙PLC使用-CSDN博客 CIP通讯介绍(欧姆龙PLC)-CSDN博客 使用NuGet添加引用:CIPCompolet 基础参考我的CIP协议介绍,默认TCP端口为:44818 类NXCompolet 类的功能可以在安装PLC开发软件后帮…

【io.net空投】交互攻略

一、io.net是什么 Io.net 是一个基于 Solana 的DePIN项目,为人工智能 (AI) 和机器学习 (ML) 公司聚合 GPU 资源。 Io.net 的例子,就是鼓励大家出借 GPU 算力,为 AI 或机器学习(ML)公司提供更低价、更有效率的算力资源…

STM32时钟树

1、STM32时钟框图

DHCP中继实验(华为)

思科设备参考: 一,技术简介 DHCP中继,可以实现在不同子网和物理网段之间处理和转发DHCP信息的功能。如果DHCP客户机与DHCP服务器在同一个物理网段,则客户机可以正确地获得动态分配的IP地址。如果不在同一个物理网段,…

Python算法题集_在排序数组中查找元素的第一个和最后一个位置

Python算法题集_在排序数组中查找元素的第一个和最后一个位置 题34:在排序数组中查找元素的第一个和最后一个位置1. 示例说明2. 题目解析- 题意分解- 优化思路- 测量工具 3. 代码展开1) 标准求解【二分法两次左边界】2) 改进版一【二分法左右边界】3) 改进版二【第三…

操作系统原理与实验——实验五时间片轮转进程调度

实验指南 运行环境: Dev c 算法思想: 将处理机的运行时间划分成等长的时间片,转轮式分配给各个就绪进程使用。 采用此算法的系统中,所有就绪进程按照先来先服务的原则排成一个队列,每次调度时将处理机分派给队首进程。…

基于梯度统计学的渐变型亮缝识别算法

作者:翟天保Steven 版权声明:著作权归作者所有,商业转载请联系作者获得授权,非商业转载请注明出处 一、场景痛点 在图像处理相关的实际工程中,会出现各式各样的现实复杂问题,有的是因为机械设计导致&#x…

图|dfs bfs|最小生成树|最短路|一篇搞定图的所有知识点

文章目录 图前言项目代码仓库图的基本概念图的表示方法邻接矩阵邻接表图的一些相关概念 图的遍历bfsdfs如果给的图不是连通图? 最小生成树Kruskal算法Prim算法 最短路径单源最短路径--Dijkstra算法单源最短路径--Bellman-Ford算法多源最短路径--Floyd-Warshall算法 …

Swift 入门学习:集合(Collection)类型趣谈-下

概览 集合的概念在任何编程语言中都占有重要的位置,正所谓:“古来聚散地,宿昔长荆棘;游人聚散中,一片湖光里”。把那一片片、一瓣瓣、一粒粒“可耐”的小精灵全部收拢、吸纳的井然有序、条条有理,怎能不让…

Elasticsearch从入门到精通-03基本语法学习

Elasticsearch从入门到精通-03基本语法学习 👏作者简介:大家好,我是程序员行走的鱼 📖 本篇主要介绍和大家一块学习一下ES基本语法,主要包括索引管理、文档管理、映射管理等内容 1.1 了解Restful ES对数据进行增、删、改、查是以…

《Effective Modern C++》- 极精简版 15-21条

本文章属于专栏《业界Cpp进阶建议整理》 继续上篇《Effective Modern C》- 极精简版 5-14条。本文列出《Effective Modern C》的15-21条的个人理解的极精简版本。 Item15、尽量使用constexpr constexpr形容对象 constexpr对象都是const,但是const对象不一定是conste…

解读BOT攻击,探索灵活高效的防护之道

回顾早期的互联网应用,由于业务流量比较小,往往单台服务器就能满足负载需求。随着互联网的流量越来越大,单服务器已经不能满足业务需求,无论它优化得再好,都较难承受大量的访问压力。支持负载均衡的技术很多&#xff0…

8. 超级终端和 Minicom

超级终端和 Minicom 在对目标板进行查看、操作或目标板和上位机进行文件传输与通信时,需要安装终端软件。通过终端软件来对目标板进行配置,或者执行目标板上的程序与主机进行通信。 下面介绍 3种终端软件,具体开发时,你仅需任意使…

大语言模型的“大”体现在哪里

大语言模型中的"大"通常体现在以下几个方面,参数数量,训练数据和计算资源: 参数数量: 大语言模型的一个显著特征是其庞大的参数数量。参数的数量决定了模型的复杂度和表示能力。更多的参数通常意味着模型可以捕捉更复…

DiffuRec扩散推荐模型笔记

1 Title DiffuRec: A Diffusion Model for Sequential Recommendation(ZIHAO LI、CHENLIANG L、AIXIN SUN)【2023 ACM Transactions on Information Systems】 2 Conclusion This paper is the first attempt to apply the diffusion model to SR, and…

ESP8266程序烧录方法(以ESPFlashDownloadTool为例)

0 工具准备 ESP8266必须包含的目标bin ESPFlashDownloadTool_v3.6.3.exe NodeMCU(ESP8266) sscom5 1 ESP8266程序烧录方法(以ESPFlashDownloadTool为例) 1.1 生成ESP8266所需的bin文件 可以参考前面所写的《安信可IDE&#xff0…

算法学习05:离散化、区间合并

算法学习05:离散化、区间合并 文章目录 算法学习05:离散化、区间合并前言需要记忆的模版:一、离散化1.例题:离散化 区间和:拓展: 二、区间合并(贪心)1.例题: 总结 前言 需要记忆的模…

【Linux】cpp-httplib库

目录 升级gcc版本 下载cpp-httplib的zip安装包,上传到服务器 ​编辑 简单使用 首先打开gittee,搜索cpp-httplib,选择其中一个即可 也可以点下方链接 cpp-httplib库:cpp-httplib: cpp-httplib (gitee.com) 注意:cpp-httplib在使用的时候需…