VB.NET linq group by匿名类型不能按预期工作

我正在玩弄LINQPad附带的一些linq样本。 在“Nutshell中的C#3.0”文件夹中,在Chater 9 – Grouping下,有一个名为“按多个键分组”的示例查询。 它包含以下查询:

from n in new[] { "Tom", "Dick", "Harry", "Mary", "Jay" }.AsQueryable() group n by new { FirstLetter = n[0], Length = n.Length } 

我将字符串“Jon”添加到数组的末尾以获得实际的分组,并得出以下结果:

C#LINQPad结果

这正是我所期待的。 然后,在LINQPad中,我去了相同查询的VB.NET版本:

 ' Manually added "Jon" from n in new string() { "Tom", "Dick", "Harry", "Mary", "Jay", "Jon" }.AsQueryable() _ group by ng = new with _ { _ .FirstLetter = n(0), _ .Length = n.Length _ } into group 

结果没有正确地将Jay / Jon组合在一起。

VB.NET LINQPad结果

把我的头发拉了一下后,我发现这篇MSDN文章讨论了VB.NET的匿名类型。 在VB.NET中,默认情况下它们是可变的,而不是C#,它们是不可变的。 在VB中,您需要添加Key关键字以使它们不可变。 所以,我将查询更改为此(注意添加Key ):

 from n in new string() { "Tom", "Dick", "Harry", "Mary", "Jay", "Jon" }.AsQueryable() _ group by ng = new with _ { _ Key .FirstLetter = n(0), _ Key .Length = n.Length _ } into group 

这给了我正确的结果:

在此处输入图像描述

所以我的问题是:

  1. 当linq进行相等比较时,为什么匿名类型的可变性/不变性很重要? 值得注意的是,在Linq-to-SQL中它根本不重要,这可能只是转换为SQL的产物。 但是在Linq-to-objects中,它显然有所不同。
  2. 为什么MS选择让VB的匿名类型变得可变。 我认为没有真正的优势,在解决了这个问题之后,我发现了一些非常明显的缺点。 即你的linq查询可能有微妙的错误。

– 编辑 –

只是一个有趣的额外信息…显然这是关键的财产问题是众所周知的。 我只是不知道Google的用途。 这里和stackoverflow上已经讨论过了。 这是使用匿名类型和Distinct的另一个问题示例:

 Dim items = New String() {"a", "b", "b", "c", "c", "c"} Dim result = items.Select(Function(x) New With {.MyValue = x}).Distinct() Dim result2 = items.Select(Function(x) New With {Key .MyValue = x}).Distinct() 'Debug.Assert(result.Count() = 3) ' Nope... it's 6! Debug.Assert(result2.Count() = 3) 

Key修饰符不仅影响可变性 – 它还会影响EqualsGetHashCode的行为。 这些计算中只包含Key属性…这明显影响分组等。

至于为什么它与VB不同 – 我不知道。 这对我来说似乎很奇怪。 我知道我很高兴C#以它的方式工作但是:)即使可以说可以使属性任意可变是有意义的,我不明白为什么它应该是默认的。