0

我有以下课程。

public class myType
{
  public event Action myAction;
}

还有一个包含该类的一些实例的字典。

var myDictionary = new Dictionary<myType, string>();

在我的 Main 我有一个带有签名的方法 void SomeMethod(myType, Dictionary)

通过以下循环,我添加了对象的行为:

foreach(var pair in myDictionary)
  pair.Key.myAction += () => SomeMethod(pair.Key, myDictionary);

运行此循环后,当调用我的一个对象的操作时,效果就好像循环已使用字典中的最后一个 pair.Key 来处理所有 lambda 表达式。

另一方面,循环中有一个小的变化:

foreach(var pair in myDictionary)
{
  myType temp = pair.Key;
  pair.Key.myAction += () => SomeMethod(temp, myDictionary);
}

运行此循环后,所有对象操作都按预期工作。

我有点不知所措,为什么这样的改变会产生这样的效果。键值对可能是一个结构,键本身是一个引用类型(我的类的一个实例)。任何想法为什么会这样?

在此先感谢您的任何建议。

4

1 回答 1

1

运行此循环后,当调用我的一个对象的操作时,效果就好像循环已使用字典中的最后一个 pair.Key 来处理所有 lambda 表达式。

是的,这正是正在发生的事情。您有一个变量pair供所有事件处理程序使用。在循环之后,变量包含循环中最后一项的键。

通过在作用域中创建一个局部变量并在 lambda 表达式中使用它,您实际上是在为每个事件处理程序创建一个闭包。局部变量不作为常规局部变量存储在堆栈中,而是存储在闭包中,并且由于每个事件处理程序都有自己的闭包,因此您会为每个事件处理程序获得一个版本的局部变量。

(第一个代码也有一个闭包,但这只是为了让变量在当前范围内存活,事件处理程序共享相同的闭包。)

于 2013-03-03T23:31:03.993 回答