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.hqwc.cn/news/525059.html

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

相关文章

管理交换机

文章目录 本地管理交换机物理交换机如何本地管理ensp上的虚拟交换机如何本地管理认证模式的三种方式 远程管理交换机配置通过Telnet登录设备配置通过STelnet登录设备 --推荐的方式检查配置结果使用Cloud管理多个交换机时 华为官网配置信息 本地管理交换机 当交换机首次使用时&…

族群争霸休闲养成小游戏

​游戏概述: 在一个由自然力量支配的幻想世界中,狼族与羊族的战争永无止境。 人族在两者之间寻求和平,建立起坚固的城墙,同时捕捉狼与羊来增强自身实力。 神族则在幕后观察,偶尔以神技介入战场,影响战局…

giffgaff怎么充值?giffgaff怎么续费?

-性价比高:0月租,免费接收短信,充值一次,接码可以用20年以上(仅需半年保号一次),可能是国内性价比最高的接码实体卡!-安全:实体卡无须担心因号码被风控,还可以…

多边形质心(centroid)的计算方法

原文代码 // polygon按顺时针排列顶点 function getCentroid(polygon) {var totalArea 0var totalX 0var totalY 0var points polygon[0]for (var i 0; i < points.length; i) {// a、b以及原点构成一个三角形var a points[i 1]var b points[i]var area 0.5 * (a[…

使用jar命令删除.jar文件中的重复的类和目录并重新打包

引言&#xff1a; android项目&#xff0c;引入的 .jar包 和 .aar中 有相同的类&#xff0c;导致编译冲突&#xff0c;由于这些依赖项没有上传到Maven仓库&#xff0c;无法使用 exclude 排除&#xff0c;只能尝试修改jar文件&#xff0c;删除重复的代码&#xff0c;再重新打包…

MySQL进阶之(五)InnoDB数据存储结构之表空间

五、InnoDB数据存储结构之表空间 5.1 数据页加载的三种方式5.1.1 内存读取5.1.2 随机读取5.1.3 顺序读取 5.2 区5.2.1 为什么要有区&#xff1f;5.2.2 碎片区5.2.3 区的分类 5.3 段5.4 表空间5.4.1 独立表空间5.4.2 系统表空间 在数据页结构中提到过&#xff0c;页的上层结构中…

poll开发服务器

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

SpringCloudGateway全局过滤器

文章目录 全局过滤器的作用自定义全局过滤器过滤器执行的顺序 上一篇 Gateway理论与实践 介绍的过滤器&#xff0c;网关提供了31种&#xff0c;但每一种过滤器的作用都是固定的。如果我们希望拦截请求&#xff0c;做自己的业务逻辑则没办法实现。 全局过滤器的作用 全局过滤器的…

影刀_如何点击桌面图片上的指定区域

问题&#xff1a;如图&#xff0c;桌面上有一张打开的图片&#xff0c;如何点击“J&T极兔快递”的左上角和右下角&#xff1f; 总体流程&#xff1a; 1、用“影刀离线OCR”指令获取目标区域坐标值。 分别是&#xff1a;x1,y1,x2,y2 2、用快捷键ctrlalt键获取图片左上角的…

CNN中的参数,计算量,FLOPs,Multi-Add(乘加),输出特征图尺寸和通道变化

在阅读论文时&#xff0c;我们会遇到参数量&#xff0c;FLOPS&#xff0c;Multi-add&#xff0c; CNN参数&#xff0c;CNN计算量等概念&#xff0c;通过阅读整理&#xff0c;这篇博客希望以最简洁的解释帮助大家理解这些基本概念。 首先&#xff0c;我们看一下卷积的计算方式&a…

DeepLearning in Pytorch|共享单车预测NN详解(思路+代码剖析)

目录 概要 一、代码概览 二、详解 基本逻辑 1.数据准备 2.设计神经网络 初版 改进版 测试 总结 概要 原文链接&#xff1a;DeepLearning in Pytorch|我的第一个NN-共享单车预测 我的第一个深度学习神经网络模型---利用Pytorch设计人工神经网络对某地区租赁单车的使用…

LeetCode中的returnSize和returnColumnSize

今天这篇比较水&#xff0c;不过本文要讲的内容是我曾经遇到过的问题&#xff0c;也可能是大部分人在初次接触力扣时的一些疑问。当时遇到这个问题也是上网找了许久没有找到满意的答案&#xff0c;现在自己明白了&#xff0c;也希望能够帮助还抱有疑惑的各位解答。 如果我说的…