[英]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
(您已合并为0
的Nothing
)。 这意味着每个匿名 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.