当我期望“1 1 1 1”时,以下代码打印“2 2 2 2”。为什么“Count()”会重新评估查询?
class Class1
{
static int GlobalTag = 0;
public Class1()
{
tag = (++GlobalTag);
}
public int tag;
public int calls = 0;
public int Do()
{
calls++;
return tag;
}
}
class Program
{
static void Main(string[] args)
{
Class1[] cls = new Class1[] { new Class1(), new Class1(), new Class1(), new Class1() };
var result = cls.Where(c => (c.Do() % 2) == 0);
if (result.Count() <= 10)
{
if (result.Count() <= 10)
{
foreach (var c in cls)
{
Console.WriteLine(c.calls);
}
}
}
}
}
答案 0 :(得分:10)
它还有什么用呢?您希望Count()
做什么来缓存值?
LINQ to Objects通常懒惰地执行,只在需要时实际评估查询 - 例如计算元素。所以对Where
的调用根本没有评估序列;它只是记住谓词和序列,以便它可以在需要时对其进行评估。
有关LINQ to Objects如何工作的更多详细信息,建议您阅读我的Edulinq blog series。它相当长(而不是完全完成)但它会让你更深入地了解LINQ to Objects的工作原理。
答案 1 :(得分:8)
并非所有序列都是可重复的,因此通常必须对它们进行计数。为了帮助它,您可以在序列上调用ToList()
- 即使键入为IEnumerable<T>
,LINQ-to-Objects仍然会快捷并使用.Count
- 因此非常便宜,重复的。
有关不可重复序列的示例:
static int evil;
static IEnumerable<int> GetSequence() {
foreach(var item in Enumerable.Range(1, Interlocked.Increment(ref evil)))
yield return item;
}
使用demo:
var sequence = GetSequence();
Console.WriteLine(sequence.Count()); // 1
Console.WriteLine(sequence.Count()); // 2
Console.WriteLine(sequence.Count()); // 3