C#怎么比较两个对象是否相等 Equals和GetHashCode重写方法

来源:这里教程网 时间:2026-02-21 17:33:32 作者:

在C#中,判断两个对象是否“逻辑相等”,不能只靠

==
或默认的
Equals()
——尤其是自定义类。关键在于正确重写
Equals(object)
GetHashCode()
,二者必须成对出现、逻辑一致。否则可能在字典、哈希集里出错,或让相等判断结果不符合预期。

为什么必须同时重写 Equals 和 GetHashCode

这两个方法是 .NET 哈希容器(如

Dictionary<tkey tvalue></tkey>
HashSet<t></t>
)正常工作的基础:

GetHashCode()
用于快速分桶:如果两个对象相等,它们的哈希码 必须相同
Equals()
用于精确比对:哈希码相同只是“可能相等”,最终靠
Equals()
确认
反之,如果
GetHashCode()
不一致,
Equals()
根本不会被调用(直接判为不等)
若只重写
Equals()
而忽略
GetHashCode()
,对象放进
Dictionary
后可能查不到自己

重写 Equals 的基本步骤

以一个简单

Person
类为例,按规范重写
Equals(object obj)

先检查
obj
是否为
null
或类型不匹配(用
obj is Person other
最简洁)
比较所有参与逻辑相等判断的字段(通常是
public
private
的值型/引用型字段)
对引用类型字段,用
Equals(a, b)
(静态方法,可安全处理
null
对值类型字段,直接用
==
即可
如果类有继承关系,需调用基类
base.Equals(obj)
示例:
public override bool Equals(object obj) {
    if (obj is Person other) {
        return Id == other.Id && 
               string.Equals(Name, other.Name, StringComparison.Ordinal) &&
               BirthDate == other.BirthDate;
    }
    return false;
}

重写 GetHashCode 的要点

哈希码不要求唯一,但要求:相等的对象必须返回相同哈希码;尽量让不等对象哈希码分布均匀(减少哈希冲突):

只基于
Equals
中用到的那些字段计算哈希
避免使用可变字段(如后续会修改的属性),否则对象加入哈希集合后修改字段,哈希码变化 → 查找失败 C# 9+ 推荐用元组解构简化写法:
return (Id, Name, BirthDate).GetHashCode();
老版本可用
HashCode.Combine(Id, Name, BirthDate)
(.NET Core 2.1+)或手动组合(如
Id.GetHashCode() ^ (Name?.GetHashCode() ?? 0) )
示例:
public override int GetHashCode() {
    return (Id, Name, BirthDate).GetHashCode();
}

额外建议和常见坑

考虑实现
IEquatable<t></t>
接口,提供类型安全的
Equals(T other)
,避免装箱,性能更好
重载
==
!=
运算符时,内部应调用
Equals()
,保持语义一致
记录类型(
record
)自动实现结构相等和哈希,适合不可变数据场景
如果类是可变的,且字段可能被修改,务必确保修改不涉及参与
Equals
判断的字段,否则哈希容器行为不可预测

基本上就这些。核心就一条:Equals 怎么比,GetHashCode 就怎么算——不多不少,不变不乱。

相关推荐