在这个LINQ查询中,使用“Select”多次的目的是什么?

6
我看到了这样的代码:

我遇到了一些这样的代码:

Dim results = From item In New List(Of Integer) From {1, 2, 3}
              Select item
              Select item

我很惊讶 Select item 两次选取是合法的。它看起来的行为方式与只有一行 Select 完全相同。我尝试将其转换为 C#,但会出现编译错误。

是否有任何理由使用多个 Select?这会导致查询表现不同吗?


选项严格打开还是关闭?我很惊讶C#会抱怨,而VB允许它,因为我认为它们在LINQ上应该共享相同的规则。 - TyCobb
@TyCobb:不,它们在各种方面都非常不同。VB查询表达式涵盖了LINQ的更多内容,并且例如VB允许您完全省略“Select”部分。 - Jon Skeet
@JonSkeet 哦,好的。感谢你的信息。 - TyCobb
3个回答

5
C# 中等价的语法如下:
var results = from item in new List<int> {1, 2, 3}
              select item into item
              select item;

这样你就可以创建一个新的作用域来“链接”查询,或者引用VB.Net文档中的话(见链接)Select子句为后续查询子句引入了一组新的范围变量(您可以查看C#关键字文档或Select VB.Net子句文档以获取更多信息和示例)


如果你喜欢 Lambda 语法(大多数人可能都是这样),那么 C# 的等效写法也可以是 var results = new List<int> {1, 2, 3}.Select(x => x).Select(y => y);。不过,对于介绍新的范围变量集合,解释得很好。 - Douglas Barbin
1
所有的回答都很好,我会点赞,但是这个被接受了,因为它链接到相关文档(并且还教给我一些关于C#的新知识)。 - default.kramer

4

我无法解释为什么允许这样做,但是通过查看编译后的IL代码,您会发现该表达式最终会调用Enumerable.Select两次。

L_0021: ldftn int32 ConsoleApplication1.Module1::_Lambda$__1(int32)
L_0027: newobj instance void [mscorlib]System.Func`2<int32, int32>::.ctor(object, native int)
L_002c: call class [mscorlib]System.Collections.Generic.IEnumerable`1<!!1> [System.Core]System.Linq.Enumerable::Select<int32, int32>(class [mscorlib]System.Collections.Generic.IEnumerable`1<!!0>, class [mscorlib]System.Func`2<!!0, !!1>)

L_0032: ldftn int32 ConsoleApplication1.Module1::_Lambda$__2(int32)
L_0038: newobj instance void [mscorlib]System.Func`2<int32, int32>::.ctor(object, native int)
L_003d: call class [mscorlib]System.Collections.Generic.IEnumerable`1<!!1> [System.Core]System.Linq.Enumerable::Select<int32, int32>(class [mscorlib]System.Collections.Generic.IEnumerable`1<!!0>, class [mscorlib]System.Func`2<!!0, !!1>)

最终,查询等同于以下内容:

Dim results = {1, 2, 3}.Select(Function(i) i).Select(Function(i) i)

2
因为展示了IL代码和等效的VB .Net lambda,所以点赞。 - Douglas Barbin

3
Sehnsucht和Bjørn-Roger Kringsjå的答案是准确的。其要点是,你正在使用Select生成结果集,然后再次使用Select根据之前的结果集生成新的结果集。在你的示例中,两个结果集是相同的,因此这与仅使用一次Select相同。
回答你的第二个问题,可能有一些情况下,你希望编写包含多个Select的查询以提高可读性或出于其他原因。一个微不足道的例子可能如下所示:
Dim results = From item In New List(Of Integer) From {1, 2, 3}
              Where item > 1
              Select item
              Where item < 3
              Select item

这将返回一个仅包含整数2的集合。显然,这可以用一个Select和一个Where(使用一个And)来实现,但有些情况下,您的条件可能非常复杂,您希望将它们分开而不是将它们作为单个Where子句的一部分。或者可能有其他需要将语句拆分成较小部分的操作。
一般来说,这种情况用得不多,但如果您需要,LINQ允许这样做,这很好。

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接