使用Distinct命令无法去除合并后JSON列表重复项的技术咨询
解决Distinct无法去除Order列表重复项的问题
这个问题我碰到过不少次——默认的Distinct()方法对引用类型的判断逻辑和你想的不一样,这就是为啥去重没生效。咱们一步步来解决:
为什么Distinct()没效果?
对于引用类型(比如你的Order类),默认的Distinct()会检查两个对象是否是同一个内存实例,而不是它们的业务属性是否相同。哪怕两个Order对象的所有字段值都完全一致,只要是从两次JSON反序列化得到的不同实例,Distinct()就会把它们当成不同的项。
解决方案
1. 重写Order类的Equals和GetHashCode方法
选一个或多个能唯一标识订单的属性(比如OrderId),基于这些属性实现相等判断:
public class Order { public int OrderId { get; set; } // 你的其他属性... // 重写Equals方法,判断业务上的相等性 public override bool Equals(object obj) { // 先判断是否是同一实例,再判断类型,最后比较关键属性 if (ReferenceEquals(this, obj)) return true; if (obj is null || GetType() != obj.GetType()) return false; Order otherOrder = (Order)obj; return OrderId == otherOrder.OrderId; } // 重写GetHashCode,基于相同的关键属性计算哈希值 public override int GetHashCode() { // 用HashCode.Combine可以方便组合多个属性(如果需要的话) return HashCode.Combine(OrderId); } }
修改后直接调用shipments.Distinct().ToList()就能正确去重了。
2. 实现IEquatable<Order>接口(更类型安全的方式)
这是推荐的做法,避免object类型转换的装箱开销,代码更清晰:
public class Order : IEquatable<Order> { public int OrderId { get; set; } // 你的其他属性... public bool Equals(Order other) { if (other is null) return false; return OrderId == other.OrderId; } // 重写基类的Equals,调用上面的类型安全版本 public override bool Equals(object obj) => Equals(obj as Order); public override int GetHashCode() => HashCode.Combine(OrderId); }
3. 使用自定义IEqualityComparer<Order>(不修改原类时用)
如果Order是第三方类或者你不想修改它的代码,可以创建一个单独的比较器:
public class OrderEqualityComparer : IEqualityComparer<Order> { public bool Equals(Order x, Order y) { if (x is null && y is null) return true; if (x is null || y is null) return false; return x.OrderId == y.OrderId; } public int GetHashCode(Order obj) { return obj.OrderId.GetHashCode(); } }
调用时传入这个比较器:
var uniqueShipments = shipments.Distinct(new OrderEqualityComparer()).ToList();
4. 用GroupBy快速去重(临时解决方案)
如果不想写额外的方法或类,可以直接用分组取首项的方式:
var uniqueShipments = shipments .GroupBy(order => order.OrderId) // 按唯一标识分组 .Select(group => group.First()) // 取每组的第一个元素 .ToList();
注意事项
- 确保你用来判断重复的属性(比如
OrderId)确实能唯一标识一个订单,如果需要多个属性组合判断(比如OrderId + ShipmentId),记得在相等判断和哈希计算里都包含这些属性。 - 如果用
HashCode.Combine,可以传入多个参数,比如HashCode.Combine(OrderId, ShipmentId)。
内容的提问来源于stack exchange,提问作者G_Man
相关产品推荐
相关产品推荐

