使用C# LINQ Intersect合并多列表为去重列表却得到空列表,求排查
问题分析与解决方案
一、核心逻辑错误:误用Intersect而非Union
你的代码初始combinedMaterialList是空列表,而Intersect的作用是求两个集合的交集——空集合和任何集合的交集必然是空,所以第一次循环后结果就为空,后续循环自然一直返回空列表。
你实际需要的是合并所有列表并去重,这应该用Union(并集操作,自动去重),或者先把所有元素合并再调用Distinct。
二、相等性判断不一致:Equals与GetHashCode逻辑不匹配
LINQ的集合操作(如Intersect/Union/Distinct)依赖对象的相等性判断,要求Equals和GetHashCode的逻辑必须完全一致:
- 你的
Equals方法仅通过ExternalId判断两个Material是否相等 - 但
GetHashCode却结合了Id、ExternalId、Name、Quantity多个属性
这种不一致会导致:即使两个对象的ExternalId相同(Equals返回true),只要其他属性不同,它们的哈希值就不同,LINQ会直接判定为不同对象,不会触发Equals比较,最终去重逻辑失效。
修正后的代码
1. 合并去重逻辑(二选一)
方式一:循环用Union合并
List<Material> combinedMaterialList = new List<Material>(); foreach (var project in projects) { combinedMaterialList = combinedMaterialList.Union(project.Materials).ToList(); }
方式二:SelectMany一次性合并(更高效)
List<Material> combinedMaterialList = projects .SelectMany(project => project.Materials) .Distinct() .ToList();
2. 修正Material类的相等性实现
必须让Equals和GetHashCode逻辑一致,同时重写object基类的Equals方法:
public int Id { get; set; } public int ExternalId { get; set; } public string? Name { get; set; } public decimal Quantity { get; set; } public bool Equals(Material? other) { if (other is null) return false; if (ReferenceEquals(this, other)) return true; // 仅通过ExternalId判断相等,和GetHashCode逻辑对齐 return GetType() == other.GetType() && ExternalId == other.ExternalId; } // 重写object的Equals,确保LINQ能正确调用 public override bool Equals(object? obj) { return Equals(obj as Material); } public override int GetHashCode() { // 仅基于ExternalId计算哈希值 return ExternalId.GetHashCode(); }
内容的提问来源于stack exchange,提问作者Blake Rivell
相关产品推荐
相关产品推荐

