遍历 List<Action> 时出现意外结果

Unexpected result when looping over List<Action>

我目前正在寻找棘手的采访片段,我发现了两个我无法解释的片段。我将它们合并在一起,这样它们就可以同时 运行。

代码如下:

using System.Collections.Generic;
public class Program
{
    public static void Main(string[] args)
    {
        var intActions = new List<Action>();
        for (int i = 0; i < 4; i++)
            intActions.Add(() => { Console.WriteLine(i); });

        foreach (var action in intActions)
            action();


        string[] strings = { "abc", "def", "ghi" };
        var stringActions = new List<Action>();
        foreach (string str in strings)
            stringActions.Add(() => { Console.WriteLine(str); });

        foreach (var action in stringActions)
            action();
    }
}

输出为:

4
4
4
4
abc
def
ghi

谁能解释一下为什么是这样的结果?我希望有四个“4”和四个“ghi”或“0123”和“abc def ghi”

您看到 4444 而不是 0123ghi ghi ghi 而不是 abc def ghi 的原因是 闭包.

传递给委托的 i 变量是由 reference 而不是 value 传递的,这意味着所有的actions 将指向变量 i 的相同内存位置和 i 的最新值(在循环的最后一次迭代中设置为 4)。

对于输出 0123,将变量复制到另一个临时变量将意味着每个操作都有一个指向单独内存位置的指针,因此产生的数字为 'expected'。

var intActions = new List<Action>();
for (int i = 0; i < 4; i++) {
    int copy = i;
    intActions.Add(() => { Console.WriteLine(copy); });
}

foreach (var action in intActions)
    action();

同样的概念适用于示例的第二部分:

string[] strings = { "abc", "def", "ghi" };
var stringActions = new List<Action>();
foreach (string str in strings) {
    var copy = str;
    stringActions.Add(() => { Console.WriteLine(copy); });
}

foreach (var action in stringActions)
    action();