列表枚举器在被放入列表时不起作用。例如,如果有两个列表(两个枚举数)
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。
我不明白第一部分是什么错误,以及如何解决它。
发布于 2017-05-26 09:39:11
这是因为List.GetEnumerator方法返回一个List.Enumerator可变结构。
当您将它赋值给一个变量并调用MoveNext和Current时,它可以工作。但是,当传递给委托时,它是通过值传递的,因此委托接收一个副本,因此调用MoveNext不影响原始的struct Current。
只是可变结构的副作用之一。
如果你改变了
x => x.GetEnumerator()至
x => (IEnumerator<int>)x.GetEnumerator()或
x => x.AsEnumerable().GetEnumerator()这两个片段都可以工作,因为现在iterators将包含返回的结构的装箱引用。
发布于 2017-05-26 09:32:13
这是因为在不工作部分运行两个单独的.ForEach()。在前面执行两个操作(MoveNext(),然后打印)。MoveNext不会因为一个很好的解释而在.Foreach()中被记住:去回答这个问题
这里:
iterators.ForEach(x => x.MoveNext());
iterators.ForEach(x => Console.WriteLine(x.Current));变成:
iterators.ForEach(x => { x.MoveNext(); Console.WriteLine(x.Current); });发布于 2017-05-26 09:38:55
List的枚举器被实现为值类型(源代码):
iterators[0].GetType().IsValueType // true这意味着-当您将迭代器传递给方法时,迭代器是通过值传递的(即,迭代器的副本被传递,而不是传递对迭代器实例的引用)。ForEach方法只是在循环中执行一个操作:
iterators.ForEach(copy => copy.MoveNext());操作委托是一种方法,因此您要将每个迭代器的副本传递给此方法。所以原始迭代器保持不变。当您第二次调用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();https://stackoverflow.com/questions/44197910
复制相似问题