为何VB.NET中此IEnumerable无法通过索引访问?(C#开发者疑问)
嘿,我完全懂你的困惑——作为C#开发者刚接触VB.NET,确实会碰到一些语法上的小惊喜(或者说小坑😅)。你遇到的问题核心在于VB.NET对IEnumerable(Of T)的索引访问语法糖有适用范围限制,而你的代码刚好踩中了这个限制。
先理清关键逻辑:
VB.NET里允许用collection(index)访问IEnumerable(Of T),这并不是因为IEnumerable(Of T)本身自带索引器——实际上它根本没有。这是VB.NET编译器提供的语法糖,会自动把collection(index)转换成Enumerable.ElementAt(Of T)(collection, index)的调用。但这个语法糖只对局部变量、方法参数这类“直接引用”的IEnumerable变量生效,当你访问的是一个属性(哪怕这个属性的类型是IEnumerable(Of T)),编译器不会触发这个转换。
回到你的代码:
在查询里,g.Group是匿名类型的一个属性(类型为IEnumerable(Of Circle)),当你写g.Group(0)时,编译器会尝试寻找这个属性返回的类型是否有默认索引器(也就是Item属性),但IEnumerable(Of Circle)并没有这个属性,所以直接编译失败。
而g.Group.ElementAt(0)是直接调用LINQ的扩展方法,不管是属性还是局部变量,只要是IEnumerable(Of T)类型就能正常工作,所以没有问题。
你可以做个小验证:如果把分组结果先赋值给局部变量,索引访问就又能用了:
' 把分组结果取出来存到局部变量 Dim firstGroup = circleGroups.First() ' 这里可以正常编译,因为firstGroup.Group是局部变量 Dim firstCircle = firstGroup.Group(0)
解决方案
对于这种属性访问的场景,有两个稳妥的选择:
- 继续使用
ElementAt(index)方法(最通用,适合所有场景) - 如果是在非查询表达式的代码里,可以先把属性值赋值给局部变量,再用索引访问(不过在LINQ的Select子句里不太方便这么做)
内容的提问来源于stack exchange,提问作者smilinger

