IEqualityComparer中GetHashCode用法疑问及集合方法表现咨询
关于PlayerEqualityComparer在LINQ Except/Distinct中的行为分析
先澄清你的误解
你对字符串GetHashCode()的理解有误:.NET中的string类型是值语义的,只要两个字符串的内容完全相同,它们的GetHashCode()返回值就一致——哪怕是两个不同的字符串实例(除非你使用了非常特殊的字符串创建方式,比如直接分配非托管内存构造字符串,但常规场景下不会遇到)。
所以你的player1和player2的Username都是"John",它们的Username.GetHashCode()结果是完全一样的。
你的PlayerEqualityComparer的正确性
你的PlayerEqualityComparer完全符合IEqualityComparer<T>的核心要求:
- 当
Equals(x,y)返回true时,GetHashCode(x)和GetHashCode(y)的返回值必然相同 - 反之,哈希码相同的对象不一定相等(这是哈希的正常特性,不影响正确性)
这是因为Equals判断的是Username的值相等,而GetHashCode直接复用了Username的哈希码,两者逻辑完全对齐。
LINQ Except/Distinct的执行逻辑
LINQ的Distinct、Except这类方法的执行流程是:
- 遍历集合中的对象,调用
GetHashCode()获取哈希码,将对象分配到对应的哈希桶中 - 对于每个哈希桶中的对象,仅当有新对象加入时,才会调用
Equals()和桶内已有的对象逐一比较 - 如果
Equals()返回true,则判定为重复项,不会加入结果集合
针对你的示例的具体行为
对于player1和player2:
- 两者的
GetHashCode()结果相同,会被分到同一个哈希桶 - 后续调用
Equals()会返回true,所以Distinct会将它们视为重复项,最终结果只保留其中一个 Except方法中,如果两个集合分别包含player1和player2,也会判定它们是相同的对象,不会出现在最终的差集里
极端情况的补充(你的代码不会触发)
假设真的出现了Equals返回true但GetHashCode返回不同值的错误实现(比如错误地让GetHashCode返回对象的引用哈希),那会导致:
- 两个相等的对象被分到不同的哈希桶
- LINQ方法不会调用
Equals()比较它们,会直接判定为不同对象 - 最终
Distinct会保留两个对象,Except也无法正确排除重复项
但你的代码不存在这个问题,因为字符串的哈希是按值计算的。
内容的提问来源于stack exchange,提问作者ALX
相关产品推荐
相关产品推荐

