我编写了一个程序,旨在从给定的起点创建一个随机数字列表。这是一个很快的脏东西,但我在玩它时发现了一个我不太明白的有趣效果。
void Main()
{
List<int> foo = new List<int>(){1,2,3};
IEnumerable<int> bar = GetNumbers(foo);
for (int i = 1; i < 3; i++)
{
foo = new List<int>(){1,2,3};
var wibble = GetNumbers(foo);
bar = bar.Concat(wibble);
}
Iterate(bar);
Iterate(bar);
}
public void Iterate(IEnumerable<int> numbers)
{
Console.WriteLine("iterating");
foreach(int number in numbers)
{
Console.WriteLine(number);
}
}
public IEnumerable<int> GetNumbers(List<int> input)
{
//This function originally did more but this is a cutdown version for testing.
while (input.Count>0)
{
int returnvalue = input[0];
input.Remove(input[0]);
yield return returnvalue;
}
}
运行的输出是:
iterating
1
2
3
1
2
3
1
2
3
iterating
也就是说我第二次遍历 bar
是空的。
我认为这与以下事实有关:我第一次迭代它清空了用于生成列表的列表,随后它使用这些现在为空的相同列表进行迭代。
我的困惑是为什么会这样?为什么我的 IEnumerables 每次枚举它们时都不从它们的默认状态开始?有人可以解释一下我到底在做什么吗?
需要明确的是,我知道我可以通过在对 GetNumbers()
的调用中添加一个 .ToList()
来解决这个问题,这会强制立即评估和存储结果。
最佳答案
您的迭代器确实从其初始状态开始。但是,它会修改它正在读取的列表,并且一旦列表被清除,您的迭代器就没有任何事情要做。基本上,考虑
var list = new List<int> { 1, 2, 3 };
var enumerable = list.Where(i => i != 2);
foreach (var item in enumerable)
Console.WriteLine(item);
list.Clear();
foreach (var item in enumerable)
Console.WriteLine(item);
enumerable
不会被 list.Clear();
改变,但它给出的结果会改变。
关于c# - yield IEnumerable 的迭代器问题,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/12095884/