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”添加到数组的末尾以获得实际的分组,并得出以下结果:
这正是我所期待的。 然后,在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组合在一起。
把我的头发拉了一下后,我发现这篇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
这给了我正确的结果:
所以我的问题是:
- 当linq进行相等比较时,为什么匿名类型的可变性/不变性很重要? 值得注意的是,在Linq-to-SQL中它根本不重要,这可能只是转换为SQL的产物。 但是在Linq-to-objects中,它显然有所不同。
- 为什么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
修饰符不仅影响可变性 – 它还会影响Equals
和GetHashCode
的行为。 这些计算中只包含Key
属性…这明显影响分组等。
至于为什么它与VB不同 – 我不知道。 这对我来说似乎很奇怪。 我知道我很高兴C#以它的方式工作但是:)即使可以说可以使属性任意可变是有意义的,我不明白为什么它应该是默认的。