我将以下代码写入文本框:
for (int ii = 0; ii < 5; ii++)
{
textBox1.Text += String.Format("Writing Line {0}{1}", ii + 1, System.Environment.NewLine);
}
我关闭了预期的输出:
Writing Line 1
Writing Line 2
Writing Line 3
Writing Line 4
Writing Line 5
但是,当我更新asyncornusly或来自此处的其他线程时:How to update the GUI from another thread in C#?
for (int ii = 0; ii < 5; ii++)
{
textBox1.BeginInvoke(new Action(() => textBox1.Text += String.Format("Writing Line {0}{1}", ii + 1 , System.Environment.NewLine)));
}
我得到了
Writing Line 5
Writing Line 5
Writing Line 5
Writing Line 5
Writing Line 5
最后一行打印5次,我希望输出与单线程同步输出匹配?
我需要更改什么才能匹配第二个线程的第一个输出?
答案 0 :(得分:2)
这是因为您在异步操作中引用了循环变量ii
。调用操作时,循环已经完成,ii
的值为4.这就是为什么你在异步版本中得到所有五个(即4 + 1)。
为ii
制作一个临时工具可以解决问题:
for (int ii = 0; ii < 5; ii++) {
var iii = ii;
textBox1.BeginInvoke(new Action(() => textBox1.Text += String.Format("Writing Line {0}{1}", iii + 1 , System.Environment.NewLine)));
}
此错误是由访问修改后的闭包引起的。有关详细信息,请参阅this Q&A。
答案 1 :(得分:0)
变量ii
被视为在循环外定义的begin。它的编译就像它看起来像这样:
int ii;
for (ii = 0; ii < 5; ii++)
{
textBox1.Text += String.Format("Writing Line {0}{1}", ii + 1, System.Environment.NewLine);
}
因此,您的lambda正在捕获共享变量,而不是值的唯一实例。你需要在循环中制作一个副本:
for (int ii = 0; ii < 5; ii++)
{
int localCopy = ii;
textBox1.Text += String.Format("Writing Line {0}{1}", localCopy + 1, System.Environment.NewLine);
}
这也是foreach
语句的问题。在C#5中,他们改变了foreach的行为,以便将变量视为在foreach
的主体内声明,因此捕获将正常工作。因此你可以写:
foreach(int ii in Enumerable.Range(0,5))
{
textBox1.BeginInvoke(new Action(() => textBox1.Text += String.Format("Writing Line {0}{1}", ii + 1 , System.Environment.NewLine)));
}
这里重点是for
和foreach
在捕获方式上的表现不同。使用for
时,变量被视为在循环之外,foreach
认为变量在(因此可以安全捕获)内。