我知道Count()
LINQ 提供的方法有一个优化,它会检查源序列是否实现ICollection<T>
,如果实现则调用Count
属性,而不是遍历整个集合。使用此优化时,底层IEnumerable<T>
不会被消耗,因此它可以被后续的其他调用消耗Count()
。
值得注意的是,接受谓词的 Count 重载不会执行此类优化,因为它必须检查每个元素的值。
现在考虑以下完整程序:
using System;
using System.Collections.Generic;
using System.Linq;
namespace count_where_issue
{
class Program
{
static void Main(string[] args)
{
IEnumerable<int> items = new List<int> {1, 2, 3, 4, 5, 6};
IEnumerable<int> evens = items.Where(y => y % 2 == 0);
int count = evens.Count();
int first = evens.First();
Console.WriteLine("count = {0}", count);
Console.WriteLine("first = {0}", first);
}
}
}
打印,
count = 3
first = 2
我的期望是 Count 需要消耗由evens
返回的整个序列,Where()
并且随后的调用evens.First()
会失败,InvalidOperationException
因为该序列不包含任何元素。
为什么这个程序会以它的方式工作?我通常不会尝试使用IEnumerable<T>
对 `Count() 的调用。依赖这种行为是不明智的吗?