1

我有以下代码...

namespace ConsoleApplication2
{
    public delegate void Task();

    class Scheduler
    {
        private List<Task> tasks = new List<Task>();

        public void AddTask(Task myTask)
        {
            tasks.Add(myTask);
        }

        public void Start()
        {
            foreach (var task in tasks)
                task();
        }
    }

    class Program
    {
        static void Main(string[] args)
        {            
            var list = new List<string>() { "A", "B", "C" };
            var scheduler = new Scheduler();
            foreach (var item in list)
            {
                scheduler.AddTask(() => { Console.WriteLine(item); });
            }
            scheduler.Start();
        }
    }
}

输出是...

C
C
C

但是,如果我将 Main 方法的 foreach 部分更改为:

    foreach (var item in list)
    {
        var i = item;
        scheduler.AddTask(() => { Console.WriteLine(i); });
    }

我得到以下输出:

A
B
C

我的愚蠢假设是两个程序都应该产生相同的输出。有人可以解释为什么它会这样吗?

4

1 回答 1

1

在您的循环的第一个版本中,当调度程序执行 Console.Writeline() 时,item 的值正在发生变化 - item 是一个局部变量,当三个任务正在执行时,其值为“C”。

在第二个版本中,您正在创建对 item 的引用,然后在任务中使用它,因此它可以正确显示当时的值。

如果您安装了 ReSharper,它会警告您“访问修改后的闭包”:这是他们对原因的解释:

http://confluence.jetbrains.com/display/ReSharper/Access+to+modified+closure

于 2013-09-25T16:54:02.847 回答