C# Equals 和 GetHashCode 方法认知及Distinct方法解析
参照:
生成 C# Equals 和 GetHashCode 方法重写 - Visual Studio (Windows) | Microsoft Learn
如何修改字符串内容 - C# | Microsoft Learn
在C#中,Equals 和 GetHashCode 方法用于对象的比较和哈希值计算。它们在值类型和值类型的行为上有所不同。
值类型(Value Types)
Equals方法:- 默认实现: 对于值类型,
Equals方法默认比较对象的值,而不是它们的引用。比如,对于结构体(struct)类型,Equals方法会比较两个结构体的每个字段的值是否相等。 - 可以覆盖: 值类型可以覆盖
Equals方法以实现自定义的比较逻辑。
- 默认实现: 对于值类型,
GetHashCode方法:- 默认实现: 值类型的
GetHashCode方法默认基于对象的字段值生成哈希码。这通常会用到GetHashCode方法的字段值,并确保相同值的对象具有相同的哈希码。 - 建议覆盖: 自定义值类型时,建议覆盖
GetHashCode方法,以确保哈希码在逻辑上与Equals方法一致。特别是如果值类型用于哈希集合(如HashSet<T>)或字典(如Dictionary<TKey, TValue>)中,正确的GetHashCode实现非常重要。
- 默认实现: 值类型的
引用类型(Reference Types)
Equals方法:- 默认实现: 对于引用类型,
Equals方法默认比较对象的引用是否相同,也就是比较对象的内存地址。如果需要比较对象的内容,需要覆盖Equals方法。 - 可以覆盖: 引用类型通常会覆盖
Equals方法以实现基于内容的比较逻辑,而不是基于引用。
- 默认实现: 对于引用类型,
GetHashCode方法:- 默认实现: 引用类型的
GetHashCode方法默认基于对象的引用生成哈希码。这通常是内存地址的哈希值。 - 建议覆盖: 当覆盖
Equals方法时,也应当相应地覆盖GetHashCode方法,以保证相等的对象具有相同的哈希码。这对使用哈希集合或字典中的对象尤为重要
- 默认实现: 引用类型的
重写Equals 和 GetHashCode 实现
目的:有时候我们需要比较的是两个对象各属性值是否相等而不是比较内存地址是否也一样。这时候我们需要对Equals 和 GetHashCode 进行重写
重写前
using System.Linq;
List<Student> list = new List<Student>(){
new Student(1,new Card(1,"小明")),new Student(2,new Card(1,"小明")),new Student(3,new Card(3,"小华")),new Student(4,new Card(2,"小李"))
};
var list2 = list.Select(s=>s.MyCard).Distinct().ToList();
Console.WriteLine();
public class Card
{
public string Str { get; set; }
public int Number { get; set; }
public Card(int num,string strs){
Str = strs;
Number = num;
} }
public class Student
{
public int No { get; set; }
public Card MyCard { get; set; }
public Student(int num, Card card)
{
MyCard = card;
No = num;
}
}
list2:出现两个小明

重写后
using System.Linq;
List<Student> list = new List<Student>(){
new Student(1,new Card(1,"小明")),new Student(2,new Card(1,"小明")),new Student(3,new Card(3,"小华")),new Student(4,new Card(2,"小李"))
};
var list2 = list.Select(s=>s.MyCard).Distinct().ToList();
Console.WriteLine();
public class Card
{
public string Str { get; set; }
public int Number { get; set; }
public Card(int num,string strs){
Str = strs;
Number = num;
}
public override int GetHashCode()
{
return Number.GetHashCode();
}
public override bool Equals(object obj)
{
return Equals(obj as Card);
}
public bool Equals(Card card)
{
return card != null &&
Number == card.Number; }
}
public class Student
{
public int No { get; set; }
public Card MyCard { get; set; }
public Student(int num, Card card)
{
MyCard = card;
No = num;
}
}
list2结果:

结论:对于引用类的集合,distinct是没办法去重的。因为distinct调用的是默认的Equals的方法,比较的是引用地址。引用地址不一样,即使各个属性一样,也是不会相等。
破解引用类型集合distinct不生效的方式有两种,第一种如上重写默认的Equals的方法,第二种是定义一个新的属性比较的Compare的方法,作为Distinct的参数
list = list.Distinct((a, b) => a.Age == b.Age && a.Name == b.Name).ToList();
性能比较:C# Linq 的三种去重方式(Distinct)_linq distinct-CSDN博客
因为我们重写了Card的
string 是一个特殊的引用类型。它被设计为不可变的(immutable),这意味着一旦创建了 string 对象,其内容不能被更改,如果有新的。
参照:字符串 - C# 编程指南 | Microsoft Learn
string 类型的 Equals 和 GetHashCode 实现
Equals方法:- 实现:
string类型的Equals方法被重写(override)以比较两个字符串的内容,而不是它们的引用。具体来说,它会检查两个字符串的字符序列是否相同。 - 逻辑: 方法会比较两个字符串的长度和每个字符。如果长度相同且每个字符都相等,则
Equals方法返回true,否则返回false。
public override bool Equals(object obj)
{
if (obj is string otherString)
{
return StringComparer.Ordinal.Equals(this, otherString);
}
return false;
}- 实现:
GetHashCode方法:- 实现:
string类型的GetHashCode方法基于字符串的内容生成哈希码。它会使用字符串中的字符序列来计算哈希值,以确保相同内容的字符串具有相同的哈希码。 - 逻辑: 通常,
GetHashCode使用字符串中的字符和其位置来计算哈希值。C# 中,string的哈希算法依赖于字符内容和排序。由于字符串是不可变的,这样的实现保证了相同的字符串内容总是会生成相同的哈希码。
public override int GetHashCode()
{
// 使用字符序列生成哈希码的实现
}- 实现:
C# Equals 和 GetHashCode 方法认知及Distinct方法解析的更多相关文章
- 重写类的Equals以及重写Linq下的Distinct方法
当自定义一个类的时候,如果需要用到对比的功能,可以自己重写Equals方法,最整洁的方法是重写GetHashCode()方法. 但是,这个方法只适用于对象自身的对比(如if(a==b))以及字典下的C ...
- 如何很好的使用Linq的Distinct方法
Person1: Id=1, Name="Test1" Person2: Id=1, Name="Test1" Person3: Id=2, Name=&quo ...
- Linq的Distinct方法的扩展
原文地址:如何很好的使用Linq的Distinct方法 Person1: Id=1, Name="Test1" Person2: Id=1, Name="Test1&qu ...
- 扩展Linq的Distinct方法动态根据条件进行筛选
声明为了方便自己查看所以引用 原文地址:http://www.cnblogs.com/A_ming/archive/2013/05/24/3097062.html Person1: Id=1, Nam ...
- Equals()和GetHashCode()方法深入了解
最近在看Jeffrey Richter的CLR Via C#,在看到GetHashCode()方法的时候,有一个地方不是特别明白,就是重写Equals()方法时为什么要把GetHashCode()方法 ...
- ( 转 ) 聊一聊C#的Equals()和GetHashCode()方法
聊一聊C#的Equals()和GetHashCode()方法 博客创建一年多,还是第一次写博文,有什么不对的地方还请多多指教. 关于这次写的内容可以说是老生长谈,百度一搜一大堆.大神可自行绕路. ...
- 聊一聊C#的Equals()和GetHashCode()方法
博客创建一年多,还是第一次写博文,有什么不对的地方还请多多指教. 关于这次写的内容可以说是老生长谈,百度一搜一大堆.大神可自行绕路. 最近在看Jeffrey Richter的CLR Via C#,在看 ...
- 我看C#的Equals()和GetHashCode()方法
首先先谈一下Equals()这个方法: Equals()方法,来自于Object,是我们经常需要重写的方法.此方法的默认实现大概是这样的: public virtual bool Equals(obj ...
- 【转载】聊一聊C#的Equals()和GetHashCode()方法
首先先谈一下Equals()这个方法: Equals()方法,来自于Object,是我们经常需要重写的方法.此方法的默认实现大概是这样的: public virtual bool Equals(obj ...
- C# Distinct方法的使用笔记
引自:http://blog.csdn.net/shaopengfei/article/details/36426763 从C# 3.0开始提供了Distinct方法,这对于集合的使用有了更为丰富的方 ...
随机推荐
- Windows下安装和配置Java JDK
1.下载地址 JDK21 Windows安装版下载地址:https://www.oracle.com/java/technologies/downloads/#jdk21-windows JDK21 ...
- vue集成amis
一.下载amis 方式一:git下载sdk.tar.gz,https://github.com/baidu/amis/releases 方式二:npm i amis 来下载,在 node_module ...
- Luogu P8710 [蓝桥杯 2020 省 AB1] 网络分析 题解 [ 绿 ] [ 带权并查集 ]
原题 分析 本题由于从一个节点发信息,同一个集合内的所有点都会收到信息,显然是一道要求维护各节点间关系的题,因此采用并查集的数据结构进行求解. 但由于维护关系的同时还要维护权值,所以采用带权并查集,它 ...
- SQL技巧:查询某个表关联的所有存储过程
SQL技巧:查询某个表关联的所有存储过程 关键字:#SQL技巧# 背景 在开发过程中,可能需要更改某一个表的数据结构,或者更新数据.但你又不太清楚会造成什么影响,迟迟不敢下手进行调整.笔者[快乐IT] ...
- 浏览器自动化与AI Agent结合项目browser-use初探
browser-use介绍 browser-use是将您的 AI 代理连接到浏览器的最简单方式.它通过提供一个强大且简单的接口来实现 AI 代理访问网站的自动化. GitHub地址:https://g ...
- Typecho 如何开启 HTTPS
一般来说,我们直接开启 HTTPS 就行,开启后进去网站后台修改网站的 URL 即可. 但是我昨天发现,我的工具箱迁移服务器之后,前台看着是很正常的,但是后台的登陆页面引入的依然的 http 标头,所 ...
- git安装教程以及生成git ssh key
问题 GitHub拉取代码需要SSH,总是忘记命令,现网百度.记录下来,以后靠自己的博文 第一步 安装git 地址: https://git-scm.com/download/win 安装它 第二步 ...
- minecraft mods descrip
1. [Advanced Finders]矿物探测器 mod 显示玩家周围附近矿石的方向(指针显示水平面上可到达的矿石) 探测地下深部矿脉(箭头显示最近矿脉的方向(上/下)) 发现大型矿床时发出信号( ...
- 遍历列表、元组或字符串的函数enumerate
这两天在处理遇到的问题,循环遍历列表中的字典并输出到excel中 查阅资料发现了一个正和我意的函数 所以周一一上班我就开始试一试 然而发现 enumerate函数只适用于列表.元组或字符串的函数 语法 ...
- 【Loongson】支持AXI总线接口
概述 支持axi接口.但其实没有burst,没有cache,没有tlb,所以仿真起来全是空泡,冲突转发相关功能正确性就测不出来. 从sram改为axi:等待时间从一拍到看信号握手 主要更改/bug处: ...