Почему я получаю неправильные результаты при вызове Func <int>? - PullRequest
6 голосов
/ 24 марта 2011

У меня есть следующий фрагмент кода в C #:

var actions = new List<Func<int>>();

IEnumerable<int> values = new List<int> { 1, 2, 3 };

foreach (int value in values)
{
    actions.Add(() => value * value);
}

foreach (var action in actions)
{
    Console.WriteLine(action()); ;
}

Console.ReadLine();

Работает нормально, но я не получаю ожидаемого результата.

Фактический результат

9,9,9

Ожидаемый результат

1,4,9

Почему я не получаю ожидаемый результат?

Ответы [ 2 ]

13 голосов
/ 24 марта 2011

Вам нужно захватить переменную внутри цикла. Прямо сейчас ваши действия с отложенным выполнением используют последнее значение value из первого цикла foreach.

var actions = new List<Func<int>>();
        IEnumerable<int> values = new List<int> { 1, 2, 3 };
        foreach (int value in values)
        {
            var v = value;
            actions.Add(() => v * v);
        }
        foreach (var action in actions)
        {
            Console.WriteLine(action()); ;
        }
        Console.ReadLine();

Обратите внимание на строку var v = value;.

12 голосов
/ 24 марта 2011

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

Простое исправление:

foreach (int value in values)
{
    int copy = value;
    actions.Add(() => copy * copy);
}

Таким образом, вы получаете новую переменную copy на каждой итерации цикла, поэтому каждое выражение делегата будет захватывать разные переменные, и на них не влияет переменная цикла (value)меняется со временем.

Эрик Липперт объясняет это хорошо в «Закрытие переменной цикла, считающейся вредной» часть вторая ).

В основномэто «гоча» в C #, на который рано или поздно почти все влюбляются.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...