Почему плохо использовать переменную итерации в выражении лямбда

Я только что написал быстрый код и заметил эту ошибку компилятора

Использование переменной итерации в выражении лямбда может иметь неожиданные результаты.
Вместо этого создайте локальную переменную в цикле и присвойте ей значение переменной итерации.

Я знаю, что это значит, и я могу легко это исправить, а не большое дело.
Но мне было интересно, почему это плохая идея использовать переменную итерации в лямбда?
Какие проблемы я могу вызвать позже?

Ответ 1

Рассмотрим этот код:

List<Action> actions = new List<Action>();

for (int i=0; i < 10; i++)
{
    actions.Add(() => Console.WriteLine(i));
}

foreach (Action action in actions)
{
    action();
}

Что вы ожидаете от печати? Очевидный ответ 0... 9 - но на самом деле он печатает 10, десять раз. Это потому, что есть только одна переменная, которая захватывается всеми делегатами. Это такое поведение, которое неожиданно.

EDIT: Я только что видел, что вы говорите о VB.NET, а не о С#. Я считаю, что VB.NET имеет еще более сложные правила, благодаря тому, как переменные сохраняют свои значения в разных итерациях. Этот пост Джареда Парсонса дает некоторую информацию о тех трудностях, которые были связаны с этим, хотя с 2007 года, поэтому реальное поведение, возможно, изменилось с тех пор.

Ответ 2

Предположим, вы имеете в виду С# здесь.

Это из-за того, как компилятор реализует закрытие. Использование переменной итерации может вызвать проблему с доступом к модифицированному закрытию (обратите внимание, что я сказал, что "может" не "будет" причиной проблемы, потому что иногда это не происходит в зависимости от того, что еще находится в методе, а иногда вы действительно хотите доступ к модифицированному закрытию).

Дополнительная информация:

http://blogs.msdn.com/abhinaba/archive/2005/10/18/482180.aspx

Еще больше информации:

http://blogs.msdn.com/oldnewthing/archive/2006/08/02/686456.aspx

http://blogs.msdn.com/oldnewthing/archive/2006/08/03/687529.aspx

http://blogs.msdn.com/oldnewthing/archive/2006/08/04/688527.aspx