C#比较两个不同泛型列表筛选差集时Contains方法不生效问题求助
两个列表比对筛选不匹配记录不生效问题排查
关联资源:
我当前需要对两个列表进行比对,第一个列表共有93条记录,第二个列表共有1条记录。已知第一个列表的第一条记录与第二个列表的记录完全一致,我希望筛选得到第一个列表中剩余的92条不匹配记录。我尝试编写了如下代码:
var grpmembersDlist = unManagedGroupsRepo.GetGroupMembers(FinalGrpsList, target, concurancyThread);//get group members based on FinalList. var grpmembersSlist = unManagedGroupsRepo.GetGroupMembersSnapshot(target);//get groupmembers from snapshot table var FinalgrpmembersList = grpmembersDlist.Where(x => !grpmembersSlist.Contains(x)).ToList();//check this group members in groupsnapshot table. get the list of groupmembers which are not present in groupsnapshot table.
但执行后FinalgrpmembersList返回的仍然是93条记录,这段代码没有达到预期效果,麻烦大家帮忙排查问题,更多信息可参考附带的图片。
问题根因
你使用的Contains方法对于引用类型默认执行引用相等性比对:即便两个GroupMember对象的所有属性值完全一致,只要它们是不同的内存实例,Contains就会判定为不相等,所以你的过滤条件没有命中任何元素,最终返回了全部93条记录。
解决方案
推荐以下三种实现方式,按优先级排序:
方式1:基于唯一属性比对(最简单高效)
先提取快照列表的唯一标识字段(比如成员ID、账号名等全局唯一字段)构建HashSet,再做过滤,时间复杂度更低:
// 示例用Id作为唯一标识,可替换为你实际业务中的相等判定字段 var snapshotIdSet = grpmembersSlist.Select(m => m.Id).ToHashSet(); var FinalgrpmembersList = grpmembersDlist.Where(m => !snapshotIdSet.Contains(m.Id)).ToList();
方式2:用Except+自定义比较器(无需修改实体类)
如果需要多字段比对且不想改动GroupMember实体的定义,可以自定义相等比较器:
// 自定义相等比较器 public class GroupMemberEqualityComparer : IEqualityComparer<GroupMember> { public bool Equals(GroupMember a, GroupMember b) { if (a == null || b == null) return false; // 按业务需要添加相等判定条件,比如同时比对Id和GroupName return a.Id == b.Id && a.GroupName == b.GroupName; } public int GetHashCode(GroupMember m) { // 和Equals的判定规则对应 return HashCode.Combine(m.Id, m.GroupName); } }
调用方式:
var FinalgrpmembersList = grpmembersDlist.Except(grpmembersSlist, new GroupMemberEqualityComparer()).ToList();
方式3:实体类实现IEquatable接口
如果你的GroupMember类全局的相等规则就是属性相等,可以直接在类定义中实现IEquatable<T>接口,后续所有默认的相等比对(包括Contains、Except等)都会自动用你的规则:
public class GroupMember : IEquatable<GroupMember> { public int Id { get; set; } public string GroupName { get; set; } // 其他属性省略 public bool Equals(GroupMember other) { if (other == null) return false; return Id == other.Id && GroupName == other.GroupName; } public override bool Equals(object obj) => Equals(obj as GroupMember); public override int GetHashCode() => HashCode.Combine(Id, GroupName); }
修改后你原来的代码不用改动就可以正常运行。
内容的提问来源于stack exchange,提问作者Promod M
相关产品推荐
相关产品推荐


