首页
学习
活动
专区
圈层
工具
发布
社区首页 >问答首页 >迭代迭代器列表linq

迭代迭代器列表linq
EN

Stack Overflow用户
提问于 2017-05-26 09:18:01
回答 3查看 975关注 0票数 1

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

代码语言:javascript
复制
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

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

EN

回答 3

Stack Overflow用户

回答已采纳

发布于 2017-05-26 09:39:11

这是因为List.GetEnumerator方法返回一个List.Enumerator可变结构。

当您将它赋值给一个变量并调用MoveNextCurrent时,它可以工作。但是,当传递给委托时,它是通过值传递的,因此委托接收一个副本,因此调用MoveNext不影响原始的struct Current

只是可变结构的副作用之一。

如果你改变了

代码语言:javascript
复制
x => x.GetEnumerator()

代码语言:javascript
复制
x => (IEnumerator<int>)x.GetEnumerator()

代码语言:javascript
复制
x => x.AsEnumerable().GetEnumerator()

这两个片段都可以工作,因为现在iterators将包含返回的结构的装箱引用。

票数 6
EN

Stack Overflow用户

发布于 2017-05-26 09:32:13

这是因为在不工作部分运行两个单独的.ForEach()。在前面执行两个操作(MoveNext(),然后打印)。MoveNext不会因为一个很好的解释而在.Foreach()中被记住:去回答这个问题

这里:

代码语言:javascript
复制
iterators.ForEach(x => x.MoveNext());
iterators.ForEach(x => Console.WriteLine(x.Current));

变成:

代码语言:javascript
复制
iterators.ForEach(x => { x.MoveNext(); Console.WriteLine(x.Current); });
票数 1
EN

Stack Overflow用户

发布于 2017-05-26 09:38:55

List的枚举器被实现为值类型(源代码):

代码语言:javascript
复制
iterators[0].GetType().IsValueType // true

这意味着-当您将迭代器传递给方法时,迭代器是通过值传递的(即,迭代器的副本被传递,而不是传递对迭代器实例的引用)。ForEach方法只是在循环中执行一个操作:

代码语言:javascript
复制
iterators.ForEach(copy => copy.MoveNext());

操作委托是一种方法,因此您要将每个迭代器的副本传递给此方法。所以原始迭代器保持不变。当您第二次调用ForEach时,原始未接触迭代器的副本将传递到那里:

代码语言:javascript
复制
iterators.ForEach(newCopy => Console.WriteLine(newCopy.Current));

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

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

代码语言:javascript
复制
iterators.ForEach(copy => { copy.MoveNext(); Console.WriteLine(copy.Current); });

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

代码语言:javascript
复制
var iterators = lists.Select(x => (IEnumerable<int>)x.GetEnumerator()).ToList();
票数 1
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/44197910

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档