Warning: file_get_contents(/data/phpspider/zhask/data//catemap/2/csharp/268.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
C# 如何避免lambda表达式中的变量捕获?_C#_Lambda - Fatal编程技术网

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

C# 如何避免lambda表达式中的变量捕获?,c#,lambda,C#,Lambda,最近我深入阅读了C#,它教会了我关于lambda表达式的知识,我一直在使用它们来获取数据,点击事件,比如: image.MouseDown+=(o ,e)=>MethodToDoSomething(DataNeededForAction); 现在的问题是在foreach循环中使用变量捕获(感谢Jon Skeet明确了这一部分:),在初始化多个具有我订阅的事件的对象时,我通常会遇到变量捕获的问题。考虑下面的例子: foreach (var game in GamesCollection)


最近我深入阅读了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

简言之,不是。您需要创建额外的存储,以保持方法闭包中的
游戏
的正确实例可用。

如果
游戏集合
列表
,您可以使用
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;
});
(编辑:请注意,C#5改变了这一点,其中,
foreach
现在有效地为每个迭代创建了一个新变量。)

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

我相信,如果C#团队从零开始,他们会采取不同的做法,但事实并非如此。见鬼。。。但是有很好的理由反对这种改变(特别是在C#N+1编译器上正常工作的代码仍然可以编译,但在C#N编译器上会给出错误的结果;对于希望使用多个编译器构建代码的开源库作者来说,这是一个非常微妙的错误源)


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

当然可以,但实际上这会在您提供给ForEach的委托参数中为GamesCollection中的每一个游戏创建一个新的引用,所以这实际上是一样的。@spender right。当我读到这个问题时,他试图避免额外的代码行,而不一定是额外的引用。我理解这是编译器的一个限制,但我想知道是否有可能改进编译器以检测它并使其自动化。有没有什么技术上的原因使这不可能?这根本不是它的工作原理。foreach只使用一个变量声明来存储枚举数.Current,它在每次传递时都会被覆盖。这就是在方法闭包中捕获的内容。我不认为它需要改变。我知道它不是这样运作的,但我想问的是,为什么要做出这样的决定。编译器可能会检测到迭代变量被捕获,并通过自动添加临时赋值对其进行解释。我看到的几乎所有使用闭包的人的问题都是由于捕获迭代变量造成的。我想问的是,为什么未来的语言/编译器无法实现自动化,是否有任何技术/逻辑上的原因,因为我想不出任何人想要捕获迭代变量的实际原因。我认为,制作一个特例将被证明是令人困惑的,而不是有益的,并且有效地需要了解两种不同的操作模式。因为这个答案是书面的,C#团队决定做出突破性的改变,在C#5中逻辑地在循环中移动循环变量(链接文章已更新)。问题中的代码现在可以工作了,而不必复制
game
变量。@AndersAbel:的确如此。不幸的是,现在有太多的答案要回去解决:(