如何避免lambda表达式中的变量捕获
本文关键字:变量 何避免 lambda 表达式 | 更新日期: 2023-09-27 17:49:33
最近我深入阅读了C#,它教会了我关于lambda表达式的知识,我一直在使用它们来解析数据以点击事件,比如:
image.MouseDown+=(o ,e)=>MethodToDoSomething(DataNeededForAction);
现在,这些问题是在foreach循环中使用变量捕获(感谢Jon Skeet非常清楚地说明了这一部分:(,在初始化具有我订阅的事件的几个对象时,我通常会遇到变量捕获的问题。考虑以下示例:
foreach (var game in GamesCollection)
{
Image img = new Image();
img.Width = 100;
img.MouseDown+=(o,e) => MyMethod(game.id);
}
为了避免在这种情况下捕获,我必须添加一些变量来分配游戏,然后将该变量传递给方法,这会产生额外的不清楚代码,而且大多会造成额外的混乱。有办法绕过这个吗?至少看起来更干净的东西?
Thx,Ziv
(编辑:请注意,这在C#5中发生了变化,其中foreach
现在有效地为每个迭代创建了一个新的变量。(
不,这是无法避免的。基本上,语言规范用单个变量而不是每次迭代用一个新变量来描述foreach
的方式是错误的。就我个人而言,就所涉及的代码量而言,我并不认为这是一个问题——当你意识到这是个问题并想好如何解决它时,你已经克服了最大的障碍。请注意,我通常会附上一条注释,让维护程序员明白这一点。
我相信,如果C#团队从头开始,他们会采取不同的做法,但事实并非如此。见鬼,他们甚至讨论过改变现有的行为。。。但有充分的理由反对这种改变(尤其是在C#N+1编译器上正常工作的代码仍然会编译,但在C#N编译器上会给出错误的结果;对于希望用多个编译器构建代码的开源库作者来说,这是一个非常微妙的错误来源(。
(希望你喜欢这本书,顺便说一句…(
简而言之,没有。您需要创建额外的存储,以在方法闭包中保持game
的正确实例可用。
如果GamesCollection
是List<T>
,则可以使用ForEach
方法:
GamesCollection.ForEach(game => {
Image img = new Image();
img.Width = 100;
img.MouseDown+=(o,e) => MyMethod(game.id);
});
但总的来说,没有。还有一个额外的变量并没有那么混乱。
先用LINQ表达式取出game.id怎么样。接通电话。Aggregate((每次都应该生成一个新变量,因为它实际上是一个方法参数。
GamesCollection.Select(game => game.id).Aggregate((_, id) => {
Image img = new Image();
img.Width = 100;
img.MouseDown+=(o,e) => MyMethod(id);
return img;
});