LINQ Distinct未调用IEquatable<T>.Equals实现的问题求解
问题原因
你的问题是GetHashCode方法实现不符合规范,同时缺少非泛型Equals(object)方法的重写,导致基于哈希的集合操作(包括Distinct)无法正确判定相等性。
为什么Contains正常但Distinct失效
List<T>.Contains的内部逻辑是遍历列表元素,逐个调用Equals方法比对,不需要预先校验对象哈希码,所以哪怕GetHashCode实现错误也不影响它的执行结果。Distinct属于基于哈希的操作,执行逻辑是先调用对象的GetHashCode方法获取哈希值:如果两个对象的哈希值不同,会直接判定为不相等,根本不会触发后续的Equals调用;只有哈希值相同时,才会调用Equals做最终的相等性校验。
你代码里的两个核心错误
GetHashCode实现完全错误
你写的public override int GetHashCode() => base.GetHashCode + this.Id;存在两个问题:
- 语法错误:
base.GetHashCode是方法组,调用需要加括号,实际运行会报错。 - 逻辑错误:就算补全括号变成
base.GetHashCode(),调用的是基类object的GetHashCode实现,该实现默认基于对象的内存地址生成哈希值,你两个new出来的Test实例哪怕Id完全相同,内存地址不同,生成的哈希值也一定不同,Distinct会直接判定为两个不同对象,不会触发你自定义的Equals逻辑。
- 缺少
object.Equals的重写
重写IEquatable<T>.Equals的同时必须配套重写非泛型的Equals(object)方法,这是.NET相等性实现的强制规范,否则部分场景下的相等比较依然会走默认的引用比较逻辑。
正确实现示例
public class Test : IEquatable<Test> { public int Id { get; init; } public bool Equals(Test other) { if (ReferenceEquals(null, other)) return false; if (ReferenceEquals(this, other)) return true; if (GetType() != other.GetType()) return false; return Id == other.Id; } // 新增重写非泛型Equals方法 public override bool Equals(object obj) { return Equals(obj as Test); } // 修正GetHashCode,仅使用参与相等比较的不可变属性生成哈希值 public override int GetHashCode() { // 单字段可直接返回字段的哈希码,多字段推荐用HashCode.Combine return HashCode.Combine(Id); } // 可选:配套重写相等运算符,符合.NET开发规范 public static bool operator ==(Test left, Test right) { return Equals(left, right); } public static bool operator !=(Test left, Test right) { return !Equals(left, right); } }
注意事项
GetHashCode的实现必须满足以下规则:
- 相等的对象必须返回相同的哈希码。
- 哈希码的生成只能依赖参与相等比较的、不可变的字段/属性,避免对象修改后哈希码变化导致哈希集合行为异常。
- 不需要保证不同对象返回的哈希码一定不同,只要相等对象哈希码相同即可,哈希冲突由后续的
Equals调用处理。
内容的提问来源于stack exchange,提问作者Alex
相关产品推荐
相关产品推荐

