繁体   English   中英

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

[英]GroupBy Anonymous Type Differences - VB.net vs C#

使用匿名类型时,我发现 C# 和 VB.net 中的 GroupBy 结果有所不同。 具体来说,当任何键为可空类型且未设置值时,VB.net 似乎无法正确分组项目。

假设我有以下 model 和一些数据:

    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# output 分组给了我 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 只给了我 1 个密钥。

    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。

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

文档中,加粗我的:

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

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

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

  • 编译器为匿名类型生成的 hash 代码算法中仅包含关键属性值。

然后继续:

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

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

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

  • 每个中的相同属性都标记为关键属性。

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

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

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

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

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM