Подтвердить что ты не робот

Локальные переменные с делегатами

Этот явно не выглядит, как будто это не будет лучшей практикой. Может кто-нибудь объяснить, почему это не будет лучшей практикой или как это работает? Любые книги или статьи, содержащие объяснения, будут оценены.

//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]: Учитывая некоторые комментарии, изменив исходное предложение...

4b9b3361

Ответ 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 (внутри) для делегата.