25

显然不是一个最佳实践。有人可以解释为什么这不是最佳实践或它是如何工作的吗?任何提供解释的书籍或文章将不胜感激。

//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"。编译器魔术的哪一部分使这项工作起作用?这就像跟踪堆上的值并稍后再次检索它一样简单吗?

[编辑]:鉴于一些评论,改变原句一些......

4

3 回答 3

30

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 在C# in Depth中有一篇非常好的文章,并在此处进行了单独(不那么详细)的讨论。

请注意,变量 currentValue 现在位于堆上,而不是堆栈上——这有很多含义,尤其是它现在可以被各种调用者使用。

这与 java 不同:在 java 中,变量的被捕获。在 C# 中,变量本身被捕获。

于 2008-09-29T13:42:57.247 回答
2

我想我要问的更多问题是它如何使用局部变量[MG编辑:“Ack - ignore this ...”后来添加]

这就是我想说的; 它真的不再是一个局部变量——至少,不是我们通常如何看待它们(在堆栈上等)。它看起来像一个,但它不是。

并且对于信息,“不是好的做法” - 匿名方法和捕获的变量实际上是一个非常强大的工具,尤其是在处理事件时。随意使用它们,但如果你走这条路,我建议你拿起 Jon 的书,以确保你了解实际发生的事情。

于 2008-09-29T13:52:24.760 回答
0

您需要在闭包/委托中捕获变量的值,否则可以修改它,就像您看到的那样。

将 currentValue 分配给委托的本地(内部)变量。

于 2008-09-29T13:45:08.660 回答