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

GroupBy匿名类型差异-VB.net与C#,c#,vb.net,linq,grouping,anonymous-types,C#,Vb.net,Linq,Grouping,Anonymous Types,当使用匿名类型时,我在C#和VB.net中遇到了GroupBy结果的差异。特别是,当任何键都是可空类型且未设置值时,VB.net似乎无法正确分组项 假设我有以下模型和一些数据: 公共类记录 { 公共int?RecordTypeId{get;set;} public int?PlayerId{get;set;} public int?TeamId{get;set;} public int?Salary{get;set;} } 公共静态类记录 { 公共静态列表记录{get;set;}=new Lis

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

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

公共类记录
{
公共int?RecordTypeId{get;set;}
public int?PlayerId{get;set;}
public int?TeamId{get;set;}
public int?Salary{get;set;}
}
公共静态类记录
{
公共静态列表记录{get;set;}=new List()
{
新记录(){PlayerId=1,Salary=100},
新记录(){PlayerId=2,Salary=200},
新记录(){PlayerId=3,Salary=300},
新记录(){PlayerId=4,Salary=400}
};
}
c#output分组给了我4个键,这是我所期望的,因为PlayerId没有重叠的值,而且它们都没有为TeamId或RecordTypeId设置值

var csharpgrouting=SomeCollection.SomeRecords.GroupBy(x=>new)
{
RecordTypeId=x.RecordTypeId.GetValueOrDefault(),
PlayerId=x.PlayerId.GetValuerDefault(),
TeamId=x.TeamId.GetValueOrDefault()
});
VB.net GroupBy只给我一个键

Dim vbGrouping=SomeCollection.SomeRecords.GroupBy(函数(x)使用{键新建_
.RecordTypeId=x.RecordTypeId.GetValueOrDefault(),\u
.PlayerId=x.PlayerId.GetValuerDefault()_
.TeamID=x.TeamID.GetValueOrDefault()_
})
但是,如果我将VB.net GroupBy更改为以下内容,并将这些键组合成一个字符串化键,它将按预期工作,我将得到4个键:

Dim stringifiedKeysGrouping=SomeCollection.SomeRecords.GroupBy(函数(x)\u
x、 RecordTypeId.GetValueOrDefault().ToString()+“-”_
+x.PlayerId.GetValueOrDefault().ToString()+“-”_
+x.TeamId.GetValueOrDefault().ToString()
)

这到底是怎么回事?我做了一些研究,了解到由于向后兼容性的原因,VB.net的可空类型与c#的不完全相同,但是我不明白这在这里是如何起作用的,因为我调用了GetValuerDefault

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

从我的,大胆的:

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

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

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

  • 对于匿名类型,编译器生成的哈希代码算法中只包含键属性值

然后继续:

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

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

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

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

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

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

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


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

从我的,大胆的:

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

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

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

  • 对于匿名类型,编译器生成的哈希代码算法中只包含键属性值

然后继续:

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

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

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

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

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

GroupBy
使用该类型的默认相等比较器。对于匿名类型
Dim vbGrouping = SomeCollection.SomeRecords.GroupBy(Function(x) New With {  _
   Key .RecordTypeId = x.RecordTypeId.GetValueOrDefault(), _ 
   Key .PlayerId = x.PlayerId.GetValueOrDefault(), _
   Key .TeamID = x.TeamId.GetValueOrDefault() _
})