为什么LINQ .Where(谓词).First()比.First(谓词)快?

我正在做一些性能testing,并注意到一个LINQexpression式

result = list.First(f => f.Id == i).Property 

比…慢

 result = list.Where(f => f.Id == i).First().Property 

这似乎是违反直觉的。 我会认为第一个expression式会更快,因为一旦谓词满足,它可以停止迭代列表,而我会认为.Where()expression式可能会在调用.First()之前迭代整个列表.First()在所得到的子集上。 即使后者发生短路,也不应该比直接使用First更快,但它是。

下面是说明这一点的两个非常简单的unit testing。 在TestWhereAndFirst上进行优化编译时,比在.Net和Silverlight 4上的TestFirstOnly快30%左右。我尝试使谓词返回更多的结果,但性能差异是相同的。

任何人都可以解释为什么.First(fn)慢于.Where(fn).First() ? 我看到类似的计数器直观的结果.Count(fn).Count(fn)相比。

 private const int Range = 50000; private class Simple { public int Id { get; set; } public int Value { get; set; } } [TestMethod()] public void TestFirstOnly() { List<Simple> list = new List<Simple>(Range); for (int i = Range - 1; i >= 0; --i) { list.Add(new Simple { Id = i, Value = 10 }); } int result = 0; for (int i = 0; i < Range; ++i) { result += list.First(f => f.Id == i).Value; } Assert.IsTrue(result > 0); } [TestMethod()] public void TestWhereAndFirst() { List<Simple> list = new List<Simple>(Range); for (int i = Range - 1; i >= 0; --i) { list.Add(new Simple { Id = i, Value = 10 }); } int result = 0; for (int i = 0; i < Range; ++i) { result += list.Where(f => f.Id == i).First().Value; } Assert.IsTrue(result > 0); } 

我得到了同样的结果:其中+第一个比第一个更快。

正如Jon指出的那样,Linq使用惰性评估,因此对于这两种方法来说,性能应该(并且)是大致相似的。

看reflection器,首先使用一个简单的foreach循环遍历集合,但Where有各种专用于不同集合types(数组,列表等)的迭代器。 大概这是什么给了那里的小优势。