Fer*_*anB 5 c# foreach delegates
假设以下代码:
foreach(Item i on ItemCollection)
{
Something s = new Something();
s.EventX += delegate { ProcessItem(i); };
SomethingCollection.Add(s);
}
Run Code Online (Sandbox Code Playgroud)
当然,这是错误的,因为所有代表都指向同一个项目.替代方案是:
foreach(Item i on ItemCollection)
{
Item tmpItem = i;
Something s = new Something();
s.EventX += delegate { ProcessItem(tmpItem); };
SomethingCollection.Add(s);
}
Run Code Online (Sandbox Code Playgroud)
在这种情况下,所有代表都指向他们自己的Item.
这种方法怎么样?还有其他更好的解决方案吗?
Eri*_*ert 11
更新:这里有关于这个问题的广泛分析和评论:
http://ericlippert.com/2009/11/12/closing-over-the-loop-variable-considered-harmful-part-one/
这是一个非常频繁报道的问题; 通常它被报告为编译器错误,但实际上编译器根据规范做了正确的事情.匿名函数关闭变量,而不是值,并且只有一个foreach循环变量.因此,每个lambda关闭同一个变量,因此获取该变量的当前值.
这对几乎每个人来说都是令人惊讶的,并且导致很多混乱和许多错误报告.我们正在考虑更改C#的假设未来版本的规范和实现,以便循环变量在循环结构中逻辑声明,每次循环都给出一个"新"变量.
这将是一个突破性的变化,但我怀疑依赖这种奇怪行为的人数很少.如果您对此主题有任何意见,请随时在上述更新中提及的博客文章中添加评论.谢谢!
第二块代码就是最好的方法,你可以让所有其他东西保持不变.
然而,有可能创建一个属性Something,其需要Item.反过来,事件代码可以从事件Item的发送者访问它,或者它可能包含在事件的eventargs中.因此消除了关闭的需要.
就个人而言,我添加了"消除不必要的关闭"作为一个有价值的重构,因为很难对它们进行推理.
| 归档时间: |
|
| 查看次数: |
1854 次 |
| 最近记录: |