Получение ссылки на ключ из KeyValuePair

У меня есть следующий класс.

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);

После запуска этого цикла, когда вызывается действие одного из моих объектов, эффект такой, как если бы цикл использовал последнюю пару. Ключ в словаре для всех лямбда-выражений.

С другой стороны, с небольшим изменением в цикле:

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

После запуска этого цикла все действия объекта работают должным образом.

Я немного в недоумении, почему такое изменение могло иметь такой эффект. Пара ключ-значение может быть структурой, сам ключ является ссылочным типом (экземпляром моего класса). Есть идеи, почему это так себя ведет?

Спасибо заранее за любые предложения.


person Bob Coder    schedule 03.03.2013    source источник


Ответы (1)


После запуска этого цикла, когда вызывается действие одного из моих объектов, эффект такой, как если бы цикл использовал последнюю пару. Ключ в словаре для всех лямбда-выражений.

Да, это именно то, что происходит. У вас есть одна переменная pair, которая используется всеми обработчиками событий. После цикла переменная содержит ключ последнего элемента цикла.

Создавая локальную переменную в области видимости и используя ее в лямбда-выражении, вы фактически создаете замыкание для каждого обработчика событий. Локальная переменная хранится не в стеке как обычная локальная переменная, а в замыкании, и поскольку у каждого обработчика событий есть собственное замыкание, вы получаете одну версию локальной переменной для каждого обработчика событий.

(Также есть замыкание с первым кодом, но это только для того, чтобы переменная выжила в текущей области, обработчики событий используют одно и то же замыкание.)

person Guffa    schedule 03.03.2013