Один из моих коллег пришел ко мне с вопросом об этом методе, который приводит к бесконечному циклу. Фактический код слишком запутан, чтобы публиковать здесь, но по существу проблема сводится к следующему:
private IEnumerable<int> GoNuts(IEnumerable<int> items)
{
items = items.Select(item => items.First(i => i == item));
return items;
}
Это должно (вы думаете) просто быть очень неэффективным способом создания копии списка. Я вызвал его с помощью:
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 => .....);
Любопытный.
Понятно, что проблема связана с переназначением параметра, но только если оценка отложена за пределами этого утверждения. Если я добавлю ToList()
, он будет работать.
У меня есть общая, неопределенная идея о том, что происходит не так. Похоже, что Select
выполняет итерацию по собственному результату. Это немного странно само по себе, потому что обычно IEnumerable
будет бросать, если изменится его итерация коллекции.
То, что я не понимаю, потому что я не очень хорошо знаком с внутренними функциями того, как работает этот материал, объясняется тем, почему повторное назначение параметра вызывает этот бесконечный цикл.
Есть ли у кого-то больше знаний о внутренностях, которые хотели бы объяснить, почему здесь происходит бесконечный цикл?