2008-09-29 2 views
22

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

//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"; 

} 

Значение, которое выводится является вторым значением «Modified». Какая часть магии компилятора делает эту работу? Это так же просто, как отслеживать значение в куче и снова извлекать его позже?

[Изменить]: С учетом некоторых замечаний, изменение первоначального предложения некоторые ...

+0

В этой практике нет ничего плохого. Он просто более продвинут, чем понимают новички. – leppie 2008-09-29 13:53:26

+0

прикованный; на самом деле, это может сделать для очень чистого/элегантного дизайна, но вам нужно понять последствия. – 2008-09-29 13:54:58

ответ

27

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# in Depth, и отдельный (не так подробно) обсуждение here.

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

Это отличное от java: в java значение значения переменной захвачено. В C# фиксируется сама переменная .

0

Вам нужно зафиксировать значение переменной в закрытии/делегировании, иначе оно может быть изменено, как вы видели.

Назначить currentValue переменной local (внутри) для делегата.

2

Я полагаю, еще вопрос я спрашиваю, что, как он работает с локальной переменной [MG редактирования: «Ack - игнорировать это ...» был добавлен позже]

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

И для информации, «не очень хорошая практика» - анонимные методы и захваченные переменные на самом деле являются невероятно мощным инструментом, особенно при работе с событиями. Не стесняйтесь использовать их, но если вы идете по этому пути, я бы рекомендовал собрать книгу Джона, чтобы вы поняли, что на самом деле происходит.

Смежные вопросы