C# Linq GroupBy对匿名与自定义类型的表现差异原因
问题根源:分组键的相等性判断逻辑差异
这个问题的核心在于匿名类型和自定义类型在Linq分组时的相等性比较规则完全不同,导致了分组结果的差异,我来给你拆解清楚:
1. 匿名类型为什么能正确分组?
C#的匿名类型有个编译器自动赋予的“隐藏福利”:它会帮你自动重写Equals()和GetHashCode()方法,而且这两个方法的判断逻辑是基于所有属性的实际值进行比较。
比如你用匿名类型作为分组键的代码:
var GroupQueryA = dt.AsEnumerable() .GroupBy(row => new { Supplier = row["Supplier"], Invoice = row["Invoice"] }) .Select(g => new { g.Key.Supplier, g.Key.Invoice, TotalAmount = g.Sum(row => row.Field<decimal>("Amount")) });
当两行数据的Supplier和Invoice值完全相同时,它们生成的匿名对象会被GroupBy判定为“相等的键”,自然会被合并到同一组,最终得到你预期的2行结果。
2. 自定义GroupKeys类型为什么分组失败?
如果你只是简单定义了一个没有重写相等性方法的自定义类型,比如:
public class GroupKeys { public object Supplier { get; set; } public object Invoice { get; set; } }
默认情况下,这个类型继承自Object类的Equals()和GetHashCode()方法,而这两个方法的默认逻辑是判断对象的引用是否相同,而非属性值是否一致。
也就是说,即使两个GroupKeys对象的Supplier和Invoice值完全一样,但它们是两个独立的实例(每次new GroupKeys()都会创建新对象),GroupBy就会把它们当成不同的分组键,原本应该合并的组被拆分开,最终得到3行结果。
3. 怎么修复自定义类型的分组问题?
要让自定义类型能正确分组,你需要手动重写Equals()和GetHashCode()方法,让相等性判断基于属性值而非对象引用:
public class GroupKeys : IEquatable<GroupKeys> { public object Supplier { get; set; } public object Invoice { get; set; } public bool Equals(GroupKeys other) { if (other is null) return false; return Equals(Supplier, other.Supplier) && Equals(Invoice, other.Invoice); } public override bool Equals(object obj) { return Equals(obj as GroupKeys); } public override int GetHashCode() { return HashCode.Combine(Supplier, Invoice); } }
这样修改后,GroupBy就会根据Supplier和Invoice的属性值来判断键是否相等,分组结果就会和匿名类型的一致了。
内容的提问来源于stack exchange,提问作者Sylwester Santorowski
相关产品推荐
相关产品推荐

