Локальные переменные с делегатами
Вопрос
Этот явно нет похоже, это не лучшая практика.Может ли кто-нибудь объяснить, почему это не лучшая практика или как это работает?Любые книги или статьи, дающие объяснение, будут оценены по достоинству.
//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";
}
Выводимое значение является вторым значением. «Модифицированный».Какая часть магии компилятора обеспечивает эту работу?Это так же просто, как отслеживать значение в куче и извлекать его позже?
[Редактировать]:Учитывая некоторые комментарии, немного изменив исходное предложение...
Решение
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";
}
Джон Скит очень хорошо написал об этом в C# в деталях, и отдельный (не такой подробный) разговор здесь.
Обратите внимание, что переменная currentValue теперь находится в куче, а не в стеке - это имеет множество последствий, не в последнюю очередь то, что теперь ее могут использовать различные вызывающие программы.
Это отличается от Java:в Java ценить переменной фиксируется.В C# сама переменная захвачен.
Другие советы
Я полагаю, что больше вопроса, который я задаю, заключается в том, что она работает с локальной переменной [MG Edit:«Ак, игнорируй это...» было добавлено позже]
В этом вся суть;Это реально не локальная переменная больше не является - по крайней мере, не в том смысле, как мы обычно о ней думаем (в стеке и т. д.).Похоже на один, но это не так.
И для информации: «нехорошая практика» — анонимные методы и захваченные переменные на самом деле являются невероятно мощным инструментом, особенно при работе с событиями.Не стесняйтесь использовать их, но если вы пойдете по этому пути, я бы порекомендовал взять книгу Джона, чтобы убедиться, что вы понимаете, что на самом деле происходит.
Вам необходимо зафиксировать значение переменной внутри замыкания/делегата, иначе его можно изменить, как вы видели.
Присвойте currentValue переменной, локальной (внутри) делегата.