我的一位同事向我提出了关于这种导致无限循环的方法的问题。实际的代码有点复杂,无法在这里发布,但本质上问题归结为:
private IEnumerable<int> GoNuts(IEnumerable<int> items)
{
items = items.Select(item => items.First(i => i == item));
return items;
}
This should(您可能会认为)只是创建列表副本的一种非常低效的方法。我用以下方式调用它:
var foo = GoNuts(new[]{1,2,3,4,5,6});
结果是无限循环。奇怪的。
我认为修改参数在风格上是一件坏事,所以我稍微改变了代码:
var foo = items.Select(item => items.First(i => i == item));
return foo;
那行得通。即程序完成;没有例外。
更多实验表明这也有效:
items = items.Select(item => items.First(i => i == item)).ToList();
return items;
就像一个简单的
return items.Select(item => .....);
Curious.
很明显,问题与重新分配参数有关,但前提是评估被推迟到该语句之外。如果我添加ToList()
有用。
我对出了什么问题有一个大致的、模糊的想法。它看起来像Select
正在迭代它自己的输出。这本身有点奇怪,因为通常IEnumerable
如果正在迭代的集合发生变化,将会抛出异常。
我不明白的是,因为我不太熟悉这个东西的工作原理,所以重新分配参数会导致这个无限循环。
有没有更了解内部原理的人愿意解释为什么这里会发生无限循环?