迭代迭代器列表linq

时间:2017-05-26 09:18:02

标签: c# linq iterator

列出的枚举器在列入列表时不起作用。例如,如果有两个列表(两个枚举器)

public void test()
{
    var firstList = new List<int>() { 1, 2, 3 };
    var secondList = new List<int>() { 4, 5, 6 };
    var lists = new List<List<int>>();
    lists.Add(firstList);
    lists.Add(secondList);

    // Not working
    var iterators = lists.Select(x => x.GetEnumerator()).ToList();
    iterators.ForEach(x => x.MoveNext());
    iterators.ForEach(x => Console.WriteLine(x.Current));

    // Working
    var firstIterator = iterators[0]; 
    var secondIterator = iterators[1];
    firstIterator.MoveNext(); secondIterator.MoveNext();
    Console.WriteLine(firstIterator.Current);
    Console.WriteLine(secondIterator.Current);
}

第一部分不起作用,它打印0 0,而第二部分正在工作,它打印1 4

我不明白第一部分的错误是什么,以及如何解决。

3 个答案:

答案 0 :(得分:6)

这是因为List<T>.GetEnumerator方法返回List<T>.Enumerator 可变结构

当您将其分配给变量并调用MoveNextCurrent时,它会起作用。但是当传递给委托时,它会按值传递,因此委托会收到一份副本,因此调用MoveNext不会影响原始struct Current

可变结构的副作用之一。

如果你改变了

x => x.GetEnumerator()

x => (IEnumerator<int>)x.GetEnumerator()

x => x.AsEnumerable().GetEnumerator()

两个片段都可以使用,因为现在iterators将包含已返回结构的盒装引用。

答案 1 :(得分:1)

因为你在不工作的部分中运行了2个单独的.ForEach()。在1 foreach(MoveNext(),然后打印)中执行两个操作。 MoveNext将不会记住.Foreach()以获得良好的解释:Go to this answer

这:

iterators.ForEach(x => x.MoveNext());
iterators.ForEach(x => Console.WriteLine(x.Current));

成为:

iterators.ForEach(x => { x.MoveNext(); Console.WriteLine(x.Current); });

答案 2 :(得分:1)

List&#39>的枚举器实现为值类型(source code):

iterators[0].GetType().IsValueType // true

这意味着 - 迭代器在将它们传递给方法时按值传递(即传递迭代器的副本而不是传递对迭代器实例的引用)。 ForEach方法只是在循环中执行一个动作:

iterators.ForEach(copy => copy.MoveNext());

Action delegate是一个方法,因此您将每个迭代器的副本传递给此方法。所以原始迭代器保持不变。当你第二次调用ForEach时,原始未触动过的迭代器的副本会在那里传递:

iterators.ForEach(newCopy => Console.WriteLine(newCopy.Current));

但原始迭代器处于初始状态(在第一项之前),这就是当您读取Current值时看到整数类型的默认值的原因。

您可以使用迭代器的单个副本:

iterators.ForEach(copy => { copy.MoveNext(); Console.WriteLine(copy.Current); });

或通过引用传递它的框值类型(请注意iterators列表的类型将更改):

var iterators = lists.Select(x => (IEnumerable<int>)x.GetEnumerator()).ToList();