简体   繁体   English

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

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

I came across a difference in the results of a GroupBy in C# and VB.net when using anonymous types.使用匿名类型时,我发现 C# 和 VB.net 中的 GroupBy 结果有所不同。 Specifically, it's that VB.net seems to have trouble correctly grouping items when any of the keys are a nullable type and have no value set.具体来说,当任何键为可空类型且未设置值时,VB.net 似乎无法正确分组项目。

Say I've got the following model and some data:假设我有以下 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}
        };
    }

The c# output grouping gives me 4 keys, which is what I expect because no items have overlapping values for PlayerId, and they all have the no value set for TeamId or RecordTypeId. 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()
            });

The VB.net GroupBy gives me only 1 key. 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() _
    })

Yet, if I change the VB.net GroupBy to the following and combine the keys into one stringified key, it works as expected and I get 4 keys:然而,如果我将 VB.net GroupBy 更改为以下并将这些键组合成一个字符串化键,它会按预期工作,我得到 4 个键:

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

What exactly is going on here?这里到底发生了什么? I did a little research and read that VB.net's nullable types are not exactly the same as c#'s, for backwards compatibility reasons, however I don't understand how that would come into play here because I am calling GetValueOrDefault.我做了一些研究并读到 VB.net 的可为空类型与 c# 的不完全相同,出于向后兼容性的原因,但是我不明白这将如何在这里发挥作用,因为我正在调用 GetValueOrDefault。

In Visual Basic, two anonymous type instances are equal if and only if they are the same type (see below) and their Key properties are all equal.在 Visual Basic 中,当且仅当它们是相同类型(见下文)并且它们的Key属性都相等时,两个匿名类型实例才相等。 If no Key properties are defined, two seemingly identical instances will compare inequal.如果没有定义Key属性,两个看似相同的实例将比较不平等。

From the documentation , bolding mine:文档中,加粗我的:

Key properties differ from non-key properties in several fundamental ways:关键属性与非关键属性在几个基本方面不同:

  • Only the values of key properties are compared in order to determine whether two instances are equal.仅比较关键属性的值以确定两个实例是否相等。

  • The values of key properties are read-only and cannot be changed.关键属性的值是只读的,不能更改。

  • Only key property values are included in the compiler-generated hash code algorithm for an anonymous type.编译器为匿名类型生成的 hash 代码算法中仅包含关键属性值。

And then continuing:然后继续:

Instances of anonymous types can be equal only if they are instances of the same anonymous type.只有当它们是相同匿名类型的实例时,匿名类型的实例才能相等。 The compiler treats two instances as instances of the same type if they meet the following conditions:如果满足以下条件,编译器会将两个实例视为相同类型的实例:

  • They are declared in the same assembly.它们在同一个程序集中声明。

  • Their properties have the same names, the same inferred types, and are declared in the same order.它们的属性具有相同的名称、相同的推断类型,并且以相同的顺序声明。 Name comparisons are not case-sensitive.名称比较不区分大小写。

  • The same properties in each are marked as key properties.每个中的相同属性都标记为关键属性。

  • At least one property in each declaration is a key property .每个声明中至少有一个属性是关键属性

GroupBy uses the default equality comparer of the type. GroupBy使用该类型的默认相等比较器。 For anonymous types it invokes the compiler generator Equals method which (as stated above) only compares the Key properties.对于匿名类型,它调用编译器生成器Equals方法,该方法(如上所述)仅比较Key属性。 In your first example you have only defined one Key property.在您的第一个示例中,您只定义了一个Key属性。 Every item in your collection has the same RecordTypeId ( Nothing which you have coalesced to 0 ).您集合中的每个项目都具有相同的RecordTypeId (您已合并为0Nothing )。 This means every anonymous object has the same single Key property all with the same value, thus one single grouping.这意味着每个匿名 object 都具有相同的单个Key属性,所有这些属性都具有相同的值,因此只有一个分组。

The solution is to make all the properties in the grouping Key properties (and not just the first):解决方案是使分组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