可能重复:
C# - The foreach identifier and closures
From Eric Lippert’s blog: “don’t close over the loop variable”
我使用lambda表达式作为ThreadStart
参数,使用Thread类在新线程中运行方法。这是我的代码:
delegate void del();
static void Do(int i)
{
Console.WriteLine(i);
}
static del CreateLoop(del Do)
{
return () =>
{
while (true)
{
Do();
Thread.Sleep(500);
}
};
}
static void Main(string[] args)
{
int n = 0;
var loop = CreateLoop(() => Do(n));
new Thread(() => loop()).Start();
Thread.Sleep(500);
n = 1;
}
这是输出:
0
1
1
1
...
怎么可能?
为什么我更改整数变量n
的值,也会更改i
(Do
参数的值)?
答案 0 :(得分:0)
您应该从中创建一个不同的变量,因此不会更改原始值。
毕竟,你所做的只是调用同样的旧'函数',lambda表达式一遍又一遍地传递变量i,这确实会改变。这就像你在某处存储var i的初始值一样。
答案 1 :(得分:0)
var loop = CreateLoop(() => Do(n));
这一行只是创建一个新函数并将其赋值给变量。除其他外,此函数将值n
传递给Do
函数。但是它没有调用Do
函数,它只是创建一个函数,在执行时会调用Do
函数。
然后启动一个调用函数等的新线程,但是新线程仍在执行Do(n)
,并将n
变量传递给Do
。那部分没有改变 - 你创建了一个引用内存中某个特定位置的函数(由变量n
表示)并继续在内存中引用该位置,即使你更改了存储在那里的值。
我相信以下内容会“修复”您的代码:
var loop = (int x) => () => CreateLoop(() => Do(x));
new Thread(loop(n)).Start();
这会将n
的值传递给loop
所代表的函数,但loop
函数会在内存中创建一个新位置(由x
表示),其中存储价值。内存中的这个新位置不会受到n
的后续更改的影响。也就是说,您创建的函数不直接引用内存中n
为指针的位置。