Eri*_*rix 0 c# dispatcher threadpool
我在Silverlight代码隐藏中有一段代码看起来像这样:
foreach (MapLocation loc in e.Result)
{
testDict[loc.ElemId] = loc.ToString();
this.Dispatcher.BeginInvoke(delegate()
{
Image icon = new Image();
icon.SetValue(Image.SourceProperty, nurseIconSource);
Canvas.SetLeft(icon, (double)loc.X * MAP_SCALE);
Canvas.SetTop(icon, MAP_HEIGHT - (double)loc.Y * MAP_SCALE);
icons[loc.ElemId] = icon;
MainCanvas.Children.Add(icon);
});
}
}
Run Code Online (Sandbox Code Playgroud)
此循环在与UI线程分开的线程上运行25次.执行该方法后,testDict对象以所有25个条目结束,而图标字典仅存储第25个(最后一个)项目的条目.
这是我第一次使用Dispatcher.它不是故意被称为快速射击吗?我能想到的是,第一次调用委托是在最后一次循环之后,因此loc对象始终是同一个项目.这准确吗?
它是旧的"不捕获循环变量"的问题.这吸引了很多人.
基本上,当委托执行它时总是使用当前值loc...并且如果你已经在委托执行之前完成了循环,那么这意味着最后的值loc显示了很多次,基本上.
解决方案是获取循环变量的副本:
foreach (MapLocation loc in e.Result)
{
MapLocation copy = loc;
testDict[loc.ElemId] = loc.ToString();
this.Dispatcher.BeginInvoke(delegate()
{
Image icon = new Image();
icon.SetValue(Image.SourceProperty, nurseIconSource);
Canvas.SetLeft(icon, (double)copy.X * MAP_SCALE);
Canvas.SetTop(icon, MAP_HEIGHT - (double)copy.Y * MAP_SCALE);
icons[copy.ElemId] = icon;
MainCanvas.Children.Add(icon);
});
}
Run Code Online (Sandbox Code Playgroud)
注意在匿名方法中使用"copy"而不是"loc".
有关更多详细信息,请阅读Eric Lippert关于"关闭循环变量被认为有害"的博客文章 - 第一部分 ; 第二部分.
| 归档时间: |
|
| 查看次数: |
1140 次 |
| 最近记录: |