GroupBy匿名类型差异-VB.net与C#

时间:2020-06-11 22:50:24

标签: c# vb.net linq grouping anonymous-types

在使用匿名类型时,我在C#和VB.net中遇到了GroupBy结果的差异。特别是,当任何键都是可空类型且未设置任何值时,VB.net似乎无法正确分组项目。

说我有以下模型和一些数据:

    public class Record
    {
        public int? RecordTypeId { get; set; }
        public int? PlayerId { get; set; }
        public int? TeamId { get; set; }
        public int? Salary { get; set; }
    }

    public static class SomeRecords
    {
        public static List<Record> Records{ get; set; } = new List<Record>()
        {
            new Record() {PlayerId = 1, Salary = 100},
            new Record() {PlayerId = 2, Salary = 200},
            new Record() {PlayerId = 3, Salary = 300},
            new Record() {PlayerId = 4, Salary = 400}
        };
    }

c#输出分组给了我4个键,这是我期望的,因为没有任何项的PlayerId值重叠,并且它们的TeamId或RecordTypeId都没有设置值。

    var cSharpGrouping = SomeCollection.SomeRecords.GroupBy(x => new
            {
                RecordTypeId = x.RecordTypeId.GetValueOrDefault(),
                PlayerId = x.PlayerId.GetValueOrDefault(),
                TeamId  = x.TeamId.GetValueOrDefault()
            });

VB.net GroupBy只给我一把钥匙。

    Dim vbGrouping = SomeCollection.SomeRecords.GroupBy(Function(x) New With { Key _
    .RecordTypeId = x.RecordTypeId.GetValueOrDefault(), _ 
    .PlayerId = x.PlayerId.GetValueOrDefault(), _
    .TeamID = x.TeamId.GetValueOrDefault() _
    })

但是,如果我将VB.net GroupBy更改为以下内容,并将密钥组合为一个字符串化密钥,则它可以按预期工作,并且我得到4个密钥:

    Dim stringifiedKeysGrouping = SomeCollection.SomeRecords.GroupBy(Function(x) _ 
    x.RecordTypeId.GetValueOrDefault().ToString() + "-" _
    + x.PlayerId.GetValueOrDefault().ToString() + "-" _
    + x.TeamId.GetValueOrDefault().ToString()
    )

这到底是怎么回事?我做了一些研究,发现由于向后兼容的原因,VB.net的可为空的类型与c#的类型并不完全相同,但是由于我正在调用GetValueOrDefault,所以我不明白在这里它会如何发挥作用。

1 个答案:

答案 0 :(得分:3)

在Visual Basic中,当且仅当两个匿名类型实例是同一类型(请参见下文)并且它们的Key属性都相等时,两个匿名类型实例才相等。如果未定义Key属性,则两个看似相同的实例将比较不相等。

documentation中以粗体显示我的位置:

关键属性与非关键属性在几个基本方面不同:

  • 仅比较键属性的值以确定两个实例是否相等。

  • 键属性的值是只读的,不能更改。

  • 编译器生成的用于匿名类型的哈希码算法中仅包含关键属性值。

然后继续:

只有匿名类型的实例是相同匿名类型的实例时,它们才能相等。如果满足以下条件,则编译器会将两个实例视为相同类型的实例:

  • 它们在同一程序集中声明。

  • 它们的属性具有相同的名称,相同的推断类型,并且以相同的顺序声明。名称比较不区分大小写。

  • 每个属性都标记为关键属性。

  • 每个声明中至少有一个属性是关键属性

GroupBy使用该类型的默认相等比较器。对于匿名类型,它调用编译器生成器Equals方法(如上所述),该方法仅比较Key属性。在第一个示例中,您仅定义了一个Key属性。集合中的每个项目都具有相同的RecordTypeId(已合并为Nothing的{​​{1}})。这意味着每个匿名对象都具有相同的单个0属性,并且每个属性都具有相同的值,因此可以进行单个分组。

解决方案是使所有属性归为Key组中的属性(而不仅仅是第一个属性):

Key
相关问题