如何避免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

如何避免lambda表达式中的变量捕获

(编辑:请注意,这在C#5中发生了变化,其中foreach现在有效地为每个迭代创建了一个新的变量。(

不,这是无法避免的。基本上,语言规范用单个变量而不是每次迭代用一个新变量来描述foreach的方式是错误的。就我个人而言,就所涉及的代码量而言,我并不认为这是一个问题——当你意识到这是个问题并想好如何解决它时,你已经克服了最大的障碍。请注意,我通常会附上一条注释,让维护程序员明白这一点。

我相信,如果C#团队从头开始,他们会采取不同的做法,但事实并非如此。见鬼,他们甚至讨论过改变现有的行为。。。但有充分的理由反对这种改变(尤其是在C#N+1编译器上正常工作的代码仍然会编译,但在C#N编译器上会给出错误的结果;对于希望用多个编译器构建代码的开源库作者来说,这是一个非常微妙的错误来源(。

(希望你喜欢这本书,顺便说一句…(

简而言之,没有。您需要创建额外的存储,以在方法闭包中保持game的正确实例可用。

如果GamesCollectionList<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;
});