LINQ扩展如何脱离其他扩展

时间:2010-02-10 03:55:51

标签: c# linq

我在2006年学习了C#,并且最近试图回到它。我已经了解到他们在C#3.0中添加了一些名为LINQ Extensions的东西。现在我熟悉扩展方法,我只是在思考那些与IEnumerables相关的细节。

今天早些时候,我和我的一位同事正在讨论以下代码块是否相同:

List<int> integers;
IEnumerable<int> subResult = items.Where(i => IsPrime(i));
IEnumerable<int> orderedResult = subResult.OrderBy(i => i);

List<int> integers;
IEnumerable<int> result = items.Where(i => IsPrime(i)).OrderBy(i => i);

他告诉我最新的效率更高,因为扩展使用了后期查询它的来源。我不太清楚我明白他的意思,我想知道他是不对的。

4 个答案:

答案 0 :(得分:5)

他们是等同的。他们都使用延迟评估/后期查询。

这意味着当调用.Where方法时,它不执行列表的任何实际枚举,它只是保持对它的输入的引用以及它要检查和存储这些引用的条件。稍后在GetEnumerator的结果中调用.Where方法后,.Where即可开始行动。

.OrderBy相同。在调用.GetEnumerator之前,它实际上不会对列表进行枚举。

这些东西很难理解,但有一些非常好的方法可以了解它。首先是写一个像你一样的简单例子,最好分成多行,用一个简单的for-each循环来迭代所有项目。调试代码并逐行执行。看看调试器如何跳转。一开始它很混乱,但经过几次,你就会明白懒惰的评估是如何运作的。

Jon Skeet还有一个用于可视化LINQ的精彩演示。

https://msmvps.com/blogs/jon_skeet/archive/2008/02/20/visual-linq-watch-query-expressions-as-they-happen.aspx

答案 1 :(得分:3)

他错了。

两段代码完全相同 实际上,如果你不在其他任何地方使用subResult,它们应该在发布模式下编译为完全相同的IL。

答案 2 :(得分:1)

LINQ在IEnumerable上实现为扩展方法。您可以考虑使用LINQ查询作为两步过程。首先,定义查询,然后迭代查询。直到你实际迭代查询的第二步,它还没有执行。

这两个示例在功能上是等效的,并且在迭代结果之前它们都不会实际执行查询,此时LINQ查询运算符(WhereOrderBy)将执行返回其相应的可枚举导致另一个,最终导致执行迭代的代码。

答案 3 :(得分:0)

延迟执行和扩展方法是完全独立的概念。

没有扩展方法语法:

var result = System.Linq.Enumerable.Where(
   myList, a => a.CustomerName == "Bob");

使用扩展方法,myList似乎有一个Where方法(但它没有)。

var result = myList.Where(a => a.CustomerName == "Bob");