我有以下课程。
public class myType
{
public event Action myAction;
}
包含该类的一些实例的字典。
var myDictionary = new Dictionary<myType, string>();
在我的主要内容中我有一个带签名的方法 void SomeMethod(myType,Dictionary)
通过以下循环,我添加了对象的行为:
foreach(var pair in myDictionary)
pair.Key.myAction += () => SomeMethod(pair.Key, myDictionary);
运行此循环后,当调用其中一个对象的操作时,效果就好像循环使用了字典中的最后一对.Key来表示所有lambda表达式。
另一方面,循环中的变化很小:
foreach(var pair in myDictionary)
{
myType temp = pair.Key;
pair.Key.myAction += () => SomeMethod(temp, myDictionary);
}
运行此循环后,所有对象操作都按预期工作。
我有点不知道为什么这样的改变会产生这样的影响。 keyvaluepair可以是一个struct,键本身就是一个引用类型(我的类的一个实例)。任何想法为什么这样做?
提前感谢任何建议。
答案 0 :(得分:1)
运行此循环后,当我的一个对象的动作是 调用,效果好像循环使用了最后一对。键入 所有lambda表达式的字典。
是的,这正是发生的事情。您有一个由所有事件处理程序使用的变量pair
。在循环之后,变量包含循环中最后一项的键。
通过在作用域中创建局部变量并在lambda表达式中使用它,实际上是为每个事件处理程序创建一个闭包。局部变量不作为常规局部变量存储在堆栈中,但是在闭包中,并且由于每个事件处理程序都有自己的闭包,因此每个事件处理程序都会获得一个局部变量版本。
(第一个代码也有一个闭包,但这只是变量在当前作用域中存活,事件处理程序共享相同的闭包。)