如何确定.NET 4.8中List<IMyInterface>.Except()的元素比较规则
Except方法相等性判断规则说明
核心问题根因
.NET 中 Except 这类 LINQ 集合操作的默认相等性判断逻辑分为两步,仅重写Equals方法不会触发调用:
- 先调用元素的
GetHashCode()方法计算哈希值,两个对象哈希值不同时,直接判定为不相等,不会执行Equals方法 - 只有哈希值相等的对象,才会进一步调用
Equals方法确认是否相等
你当前只重写了Equals方法,没有同步重写GetHashCode()方法,逻辑相等的拷贝对象返回的哈希值大概率不同,自然不会触发Equals的断点,也会导致最终结果不符合预期。
默认比较规则的明确验证方法
Except 无自定义比较器重载时,默认使用 EqualityComparer<IMyInterface>.Default 作为比较规则,你可以通过以下方式确认规则逻辑:
- 直接手动调用默认比较器测试:
// 取两个逻辑相等的对象测试 var obj1 = 你的第一个对象实例; var obj2 = 拷贝生成的第二个对象实例; var defaultComparer = EqualityComparer<IMyInterface>.Default; // 先看哈希值是否一致 var hash1 = defaultComparer.GetHashCode(obj1); var hash2 = defaultComparer.GetHashCode(obj2); // 再看Equals是否返回预期结果 var isEqual = defaultComparer.Equals(obj1, obj2); - 避免调试器悬停求值的干扰:调用
Except后立刻执行.ToList()触发枚举,确保断点触发逻辑和生产运行时完全一致。
场景修复方案
方案1:补全所有实现类的方法重写
所有实现IMyInterface的类,必须同步重写GetHashCode(),返回值和你的Equals逻辑对齐,即:两个对象Equals返回true时,GetHashCode必须返回相同值。
示例代码:
// 以Arc类为例,和你现有的Equals逻辑匹配 public override int GetHashCode() { int hash = 17; foreach (var item in Key) { hash = hash * 31 + (item?.GetHashCode() ?? 0); } return hash; }
方案2:显式传入自定义比较器(更稳妥,适合多实现类场景)
统一实现一个通用的IEqualityComparer<IMyInterface>,不需要依赖每个实现类的重写逻辑,避免漏改:
public class MyInterfaceComparer : IEqualityComparer<IMyInterface> { public bool Equals(IMyInterface x, IMyInterface y) { if (ReferenceEquals(x, y)) return true; if (ReferenceEquals(x, null) || ReferenceEquals(y, null)) return false; // 按业务逻辑实现,比如判断类型+Key序列相等 if (x.GetType() != y.GetType()) return false; return x.Key.SequenceEqual(y.Key); } public int GetHashCode(IMyInterface obj) { if (obj == null) return 0; int hash = 17; foreach (var item in obj.Key) { hash = hash * 31 + (item?.GetHashCode() ?? 0); } return hash; } }
调用时显式传入比较器即可:
var difference = myList.Except(anotherList, new MyInterfaceComparer());
内容的提问来源于stack exchange,提问作者Eric Snyder
相关产品推荐
相关产品推荐

