Локальные переменные с делегатами
Этот явно не выглядит, как будто это не будет лучшей практикой. Может кто-нибудь объяснить, почему это не будет лучшей практикой или как это работает? Любые книги или статьи, содержащие объяснения, будут оценены.
//The constructor
public Page_Index() {
//create a local value
string currentValue = "This is the FIRST value";
//use the local variable in a delegate that fires later
this.Load += delegate(object sender, EventArgs e) {
Response.Write(currentValue);
};
//change it again
currentValue = "This is the MODIFIED value";
}
Выводимое значение - это второе значение "Модифицировано". Какая часть магии компилятора делает эту работу? Это так же просто, как отслеживать значение в куче и снова извлекать его позже?
[Edit]: Учитывая некоторые комментарии, изменив исходное предложение...
Ответы
Ответ 1
currentValue больше не является локальной переменной: это захваченная переменная. Это скомпилируется примерно так:
class Foo {
public string currentValue; // yes, it is a field
public void SomeMethod(object sender, EventArgs e) {
Response.Write(currentValue);
}
}
...
public Page_Index() {
Foo foo = new Foo();
foo.currentValue = "This is the FIRST value";
this.Load += foo.SomeMethod;
foo.currentValue = "This is the MODIFIED value";
}
У Jon Skeet есть действительно хорошая запись об этом в С# в глубине, а отдельное (не так подробно) обсуждение здесь.
Обратите внимание, что переменная currentValue теперь находится в куче, а не в стеке - это имеет множество последствий, не в последнюю очередь, что теперь она может использоваться различными вызывающими абонентами.
Это отличается от java: в java значение переменной фиксируется. В С# сама переменная захватывается.
Ответ 2
Я полагаю, что вопрос, который я задаю, заключается в том, как он работает с локальной переменной [MG edit: "Ack - ignore this..." был добавлен впоследствии]
Это точка; это действительно не локальная переменная больше - по крайней мере, не с точки зрения того, как мы обычно думаем о них (в стеке и т.д.). Он выглядит как один, но это не так.
И для информации re "not good practice" - анонимные методы и захваченные переменные на самом деле являются невероятно мощным инструментом, особенно при работе с событиями. Не стесняйтесь использовать их, но если вы идете по этому пути, я бы рекомендовал собрать книгу Джона, чтобы убедиться, что вы понимаете, что на самом деле происходит.
Ответ 3
Вам нужно зафиксировать значение переменной в закрытии/делегировании, иначе оно может быть изменено, как вы видели.
Назначьте currentValue переменной local (внутри) для делегата.