gpt4 book ai didi

c# - 为什么 Enumerable.Range 被迭代两次?

转载 作者:太空狗 更新时间:2023-10-30 00:31:52 24 4
gpt4 key购买 nike

我知道 IEnumerable 是惰性的,但我不明白为什么 Enumerable.Range 在这里被迭代两次:

using System;
using System.Collections.Generic;
using System.Linq;

namespace ConsoleApplication
{
class Program
{
static int GetOne(int i)
{
return i / 2;
}

static IEnumerable<int> GetAll(int n)
{
var items = Enumerable.Range(0, n).Select((i) =>
{
Console.WriteLine("getting item: " + i);
return GetOne(i);
});

var data = items.Select(item => item * 2);

// data.Count does NOT causes another re-iteration
Console.WriteLine("first: items: " + data.Count());
return data;
}

static void Main()
{
var data = GetAll(3);

// data.Count DOES cause another re-iteration
Console.WriteLine("second: items: " + data.Count());
Console.ReadLine();
}
}
}

结果:

getting item: 0
getting item: 1
getting item: 2
first: items: 3
getting item: 0
getting item: 1
getting item: 2
second: items: 3

为什么在“第一种”情况下没有重复,但在“第二种”情况下重复?

最佳答案

您正在对 Count 触发重新迭代(为了提供答案,需要对源进行完整迭代)。一个IEnumerable永远不会保留它的值(value)观,并且会在需要时始终重申。

在诸如 Array 之类的东西之上或 List<T>这不是一个问题,但是当实现是在一个查询上,或者在一个复杂的 yield return 上时结构或其他一些代码集(例如 Enumerable.Range ),它可能可能变得昂贵。

这就是为什么 ReSharper 会警告您多重枚举之类的事情。

如果需要记住Count的结果使用变量。如果你想防止枚举昂贵的来源,你倾向于做类似 var myCachedValues = myEnumerable.ToArray() 的事情。然后转向迭代数组(从而保证只有一次迭代)。

如果你想走愚蠢的路线(就像我做的那样),你可以实现一个枚举器,在内部缓存列表中的东西,这样你就可以获得延迟执行的任何好处,以及至少迭代一次缓存的好处一次。我叫它IRepeatable .为此,我受到了同事们的严厉斥责,但我很固执。

关于c# - 为什么 Enumerable.Range 被迭代两次?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/21750561/

24 4 0