参照:

生成 C# Equals 和 GetHashCode 方法重写 - Visual Studio (Windows) | Microsoft Learn

如何修改字符串内容 - C# | Microsoft Learn

在C#中,Equals 和 GetHashCode 方法用于对象的比较和哈希值计算。它们在值类型和值类型的行为上有所不同。

值类型(Value Types)

  1. Equals 方法:

    • 默认实现: 对于值类型,Equals 方法默认比较对象的值,而不是它们的引用。比如,对于结构体(struct)类型,Equals 方法会比较两个结构体的每个字段的值是否相等。
    • 可以覆盖: 值类型可以覆盖 Equals 方法以实现自定义的比较逻辑。
  2. GetHashCode 方法:

    • 默认实现: 值类型的 GetHashCode 方法默认基于对象的字段值生成哈希码。这通常会用到 GetHashCode 方法的字段值,并确保相同值的对象具有相同的哈希码。
    • 建议覆盖: 自定义值类型时,建议覆盖 GetHashCode 方法,以确保哈希码在逻辑上与 Equals 方法一致。特别是如果值类型用于哈希集合(如 HashSet<T>)或字典(如 Dictionary<TKey, TValue>)中,正确的 GetHashCode 实现非常重要。

引用类型(Reference Types)

  1. Equals 方法:

    • 默认实现: 对于引用类型,Equals 方法默认比较对象的引用是否相同,也就是比较对象的内存地址。如果需要比较对象的内容,需要覆盖 Equals 方法。
    • 可以覆盖: 引用类型通常会覆盖 Equals 方法以实现基于内容的比较逻辑,而不是基于引用。
  2. 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 实现

  1. 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;
    }
  2. GetHashCode 方法:

    • 实现: string 类型的 GetHashCode 方法基于字符串的内容生成哈希码。它会使用字符串中的字符序列来计算哈希值,以确保相同内容的字符串具有相同的哈希码。
    • 逻辑: 通常,GetHashCode 使用字符串中的字符和其位置来计算哈希值。C# 中,string 的哈希算法依赖于字符内容和排序。由于字符串是不可变的,这样的实现保证了相同的字符串内容总是会生成相同的哈希码。
    public override int GetHashCode()
    {
    // 使用字符序列生成哈希码的实现
    }

C# Equals 和 GetHashCode 方法认知及Distinct方法解析的更多相关文章

  1. 重写类的Equals以及重写Linq下的Distinct方法

    当自定义一个类的时候,如果需要用到对比的功能,可以自己重写Equals方法,最整洁的方法是重写GetHashCode()方法. 但是,这个方法只适用于对象自身的对比(如if(a==b))以及字典下的C ...

  2. 如何很好的使用Linq的Distinct方法

    Person1: Id=1, Name="Test1" Person2: Id=1, Name="Test1" Person3: Id=2, Name=&quo ...

  3. Linq的Distinct方法的扩展

    原文地址:如何很好的使用Linq的Distinct方法 Person1: Id=1, Name="Test1" Person2: Id=1, Name="Test1&qu ...

  4. 扩展Linq的Distinct方法动态根据条件进行筛选

    声明为了方便自己查看所以引用 原文地址:http://www.cnblogs.com/A_ming/archive/2013/05/24/3097062.html Person1: Id=1, Nam ...

  5. Equals()和GetHashCode()方法深入了解

    最近在看Jeffrey Richter的CLR Via C#,在看到GetHashCode()方法的时候,有一个地方不是特别明白,就是重写Equals()方法时为什么要把GetHashCode()方法 ...

  6. ( 转 ) 聊一聊C#的Equals()和GetHashCode()方法

    聊一聊C#的Equals()和GetHashCode()方法   博客创建一年多,还是第一次写博文,有什么不对的地方还请多多指教. 关于这次写的内容可以说是老生长谈,百度一搜一大堆.大神可自行绕路. ...

  7. 聊一聊C#的Equals()和GetHashCode()方法

    博客创建一年多,还是第一次写博文,有什么不对的地方还请多多指教. 关于这次写的内容可以说是老生长谈,百度一搜一大堆.大神可自行绕路. 最近在看Jeffrey Richter的CLR Via C#,在看 ...

  8. 我看C#的Equals()和GetHashCode()方法

    首先先谈一下Equals()这个方法: Equals()方法,来自于Object,是我们经常需要重写的方法.此方法的默认实现大概是这样的: public virtual bool Equals(obj ...

  9. 【转载】聊一聊C#的Equals()和GetHashCode()方法

    首先先谈一下Equals()这个方法: Equals()方法,来自于Object,是我们经常需要重写的方法.此方法的默认实现大概是这样的: public virtual bool Equals(obj ...

  10. C# Distinct方法的使用笔记

    引自:http://blog.csdn.net/shaopengfei/article/details/36426763 从C# 3.0开始提供了Distinct方法,这对于集合的使用有了更为丰富的方 ...

随机推荐

  1. Iceberg根据快照查看文件,根据文件查看哪个快照写入

    一.背景 用户查询iceberg表时报文件为空,因为存在写入和治理程序同时操作iceberg表,需要查看空文件是哪个快照产生的,方便确定是flink写入缺陷还是spark治理缺陷 二.通过Sql查询文 ...

  2. FLink写入Clickhouse优化

    一.背景 ck因为有合并文件操作,适合批量写入.如单条插入则速度太慢 二.Flink写入ck优化 改为分批插入,代码如下 DataStream<Row> stream = ... stre ...

  3. mysql之我的第一个jdbc程序

    package com.yeyue.lesson01; import java.sql.*; public class jdbcFirstDemo { public static void main( ...

  4. 基于iscsi存储池

    命令行 [root@kvm1 ~]# virsh pool-define-as --name stor2 --type iscsi \ > --source-host 192.168.114.1 ...

  5. OceanBase Docker 初体验

    内存需求 内存10G,OB需要8G,4个逻辑CPU 卸载docker组件 yum remove docker \ docker-client \ docker-client-latest \ dock ...

  6. 中国最难入职的IT公司排行榜

    在IT行业竞争日益白热化的今天,头部企业的招聘门槛不断刷新求职者的认知.根据最新行业调研和招聘数据,我们整理出2025年中国最难入职的几家互联网公司,并揭秘其背后严苛的选拔逻辑. 通常衡量难不难,会从 ...

  7. 八米云高收益PCDN-N1设备重要通知

    八米云单价: 电联2400元/G/月 移动1500元/G/月 新上机设备[必须使用新镜像]上机!否则无业务下发! 再次强调!如6.18日后台镜像更新后–还在使用旧镜像新上机,请务必于[6月30日]前用 ...

  8. deepseek: php测试代码执行用时

    在 PHP 中,你可以使用 microtime() 函数来测量代码的执行时间.microtime() 函数返回当前 Unix 时间戳的微秒数.你可以在代码的开始和结束处分别调用 microtime() ...

  9. 多智能体粒子环境(Multi-Agent Particle Env)食用指南--从入门到入土

    0.项目地址: 原地址:openai/multiagent-particle-envs: Code for a multi-agent particle environment used in the ...

  10. Windows编程----线程管理

    系统中,进程主要有两部分组成:进程内核对象和进程地址空间.操作系统通过进程内核对象来管理进程,进程地址空间用于维护进程所需的资源:如代码.全局变量.资源文件等. 那么线程也是有两部分组成:线程内核对象 ...