带委托的局部变量

时间:2020-03-06 14:52:25  来源:igfitidea点击:

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

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

[编辑]:给定一些注释,将原始句子更改一些...

解决方案

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)在Cin Depth上对此进行了很好的撰写,在这里进行了单独的(不那么详细)讨论。

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

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

我们需要在闭包/委托中捕获变量的值,否则可以像我们看到的那样对其进行修改。

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

I suppose more the question I am asking is that how is it working with a local variable
  [MG edit: "Ack - ignore this..." was added afterwards]

这就是我想说的;至少在我们通常如何看待它们(在堆栈上等)方面,它实际上至少不再是局部变量。它看起来像一个,但事实并非如此。

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