c# - yield IEnumerable 的迭代器问题

标签 c# ienumerable yield-return

我编写了一个程序,旨在从给定的起点创建一个随机数字列表。这是一个很快的脏东西,但我在玩它时发现了一个我不太明白的有趣效果。

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/

相关文章:

c# - 在一行中创建 IEnumerable 并将其传递给方法

c# - IEqualityComparer 和 Contains 方法

c# - 将值附加到现有 IEnumerable 的末尾时产生返回

C#惰性执行+内存理解

c# - 调用者未获得 'finished' 的“yield”枚举 - 会发生什么

c# - 调用 Console.WriteLine(ex.Message) 以防止出现警告消息

c# - 使用 Linq 有条件地删除 XML 文档的部分

c# - MVC 到 Azure Active Directory 登录回复 "Bad Request"和消息 "Unable to create to obtain configuration from"

.net - IEnumerable 为空?

c# - 使用 LINQ 按类属性区分