LINQ使用匿名类型的GroupBy功能表现比预期更好

3
假设我定义了一个类如下:

class MyClass:

public class DataHolder
{
    public string PropA { get; set; }
    public string PropB { get; set; }
    public string PropC { get; set; }
    public int PropD { get; set; }
}

并声明一个DataHolder数组的实例:

    var x=new DataHolder[]{
        new DataHolder(){PropA="A",PropB="X",PropC="J",PropD=1},
        new DataHolder(){PropA="A",PropB="Y",PropC="J",PropD=3},
        new DataHolder(){PropA="A",PropB="Y",PropC="J",PropD=5},
        new DataHolder(){PropA="B",PropB="X",PropC="K",PropD=7},
        new DataHolder(){PropA="B",PropB="Y",PropC="L",PropD=9},
        new DataHolder(){PropA="C",PropB="X",PropC="J",PropD=11},
        new DataHolder(){PropA="C",PropB="X",PropC="J",PropD=13},
        new DataHolder(){PropA="C",PropB="Y",PropC="J",PropD=15},
        new DataHolder(){PropA="C",PropB="Z",PropC="J",PropD=17}
    };

然后我使用LINQ的GroupBy查询对其进行查询,如下所示:

    var t = x.GroupBy(c => new { A = c.PropA, B = c.PropB, C = c.PropC })

当我检查结果时,我发现t有7个元素,这是数组中不同PropA、PropB、PropC组合的数量,这正是我想要的效果(耶!)。但是我想,它实际上不应该起作用,因为每个新的匿名类型实例都应该与其他实例不相等,所以t应该有9个元素。为什么它按照我最初的想法工作?


由于匿名类型的Equals和GetHashCode方法是基于属性的Equals和GetHashCode方法定义的,所以只有当它们的所有属性都相等时,两个相同匿名类型的实例才相等。 - Tim Schmelter
2个回答

7

针对匿名类型:

因为匿名类型的 Equals 和 GetHashCode 方法是根据属性的 Equals 和 GetHashcode 方法定义的,所以只有当所有属性都相等时,两个同一类型的匿名类型实例才相等。

(摘自 MSDN)

因此它们确实具有重载的 Equals 方法,可以进行逐个属性的“合理”比较。


1
请按照相同的顺序定义属性(我已经添加了一个答案来注意这个问题)。 - Eren Ersönmez

6
请注意,如果两个匿名类型同时满足以下条件,则它们是“相等”的:
1)它们是相同的类型MSDN:“如果程序集中的两个或多个匿名对象初始化器指定了一个在相同顺序和具有相同名称和类型的属性序列,则编译器将对象视为同一类型的实例。它们共享相同的编译器生成的类型信息。”)
2)它们所有的属性都是相等的。
请注意,“相同的顺序”在这里很重要:
var a = new {A = 1, B = "Dog"};
var b = new {A = 1, B = "Dog"};
var c = new {B = "Dog", A = 1};

a.Equals(b) // true
a.Equals(c) // false -- a and c are instances of different types.

1
同一页面上我链接的那个段落中提到:“如果一个程序集中的两个或多个匿名对象初始化器指定了一个相同顺序、相同名称和类型的属性序列,则编译器将这些对象视为同一类型的实例。它们共享相同的编译器生成的类型信息。”但由于他在单个“GroupBy”表达式中创建了匿名对象,所以这并不相关。 - xanatos
当然,由于在我的情况下匿名类型是由相同的lambda表达式生成的,因此属性始终会按照相同的顺序出现。 - Boluc Papuccuoglu
这是错误的:“应该添加到末尾”...并且按相同顺序定义”。因为如引用所述,它们必须是“相同匿名类型的两个实例”,如果您以不同的顺序声明字段,则被视为不同类型。 - NPSF3000
@NPSF3000没错,我试图澄清这一点(请参见编辑)。 - Eren Ersönmez

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接