具有委托的局部变量

Local variables with Delegates

提问人:hugoware 提问时间:9/29/2008 最后编辑:trincothugoware 更新时间:6/13/2021 访问量:12877

问:

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

//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”。编译器魔力的哪一部分使这项工作得以实现?这是否就像跟踪堆上的值并在以后再次检索它一样简单?

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

C# 委托 闭包 堆内存

评论

0赞 leppie 9/29/2008
这种做法没有错。它只是比初学者理解的更高级。
0赞 Marc Gravell 9/29/2008
借调;事实上,它可以带来非常干净/优雅的设计 - 但你确实需要了解其中的含义。
0赞 hugoware 9/29/2008
这真的很有意思。我不认为在委托分配的范围内弄乱局部变量会是一种好的做法,但你总是能学到新的东西。
0赞 Marc Gravell 9/29/2008
这取决于情况;在大多数情况下,制作第二个变量会是一个更好的主意,该变量的范围很窄,从不改变 - 但是更新捕获的变量有一些用例,但事实上:将它们视为只读,直到有充分的理由,你会少得多的痛苦。
0赞 Brad Wilson 9/30/2008
这就是委托和关闭之间的区别。你在这里所做的是一个闭合。它们非常强大,而且我们在 .NET 中拥有闭包这一事实是一个巨大的优势,而不是一个缺点。

答:

32赞 Marc Gravell 9/29/2008 #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 在 C# 中对此进行了深入的介绍,并在此处进行了单独的(不那么详细)的讨论。

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

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

评论

0赞 Jon Skeet 9/29/2008
除了用 C# 深入编写它(感谢插件!)之外,我还有一篇文章比较了 C# 和 Java 闭包,并解释了为什么它们很好: csharpindepth.com/Articles/Chapter5/Closures.aspx
0赞 Marc Gravell 9/29/2008
啊 - 当你写那条评论时,我正在编辑上面的内容以包含它。将值加倍;-p
0赞 chiccodoro 10/7/2010
@Mark:为了稍微改善你的回答,你能在最后一句话中将“变量”换成“变量”吗?由于该变量被称为“currentValue”,它可能会使读者(像我一样)感到困惑,首先认为斜体“”指的是变量的名称(“哪个变量?那个叫做 ")
1赞 Prashant Cholachagudda 10/7/2010
我推荐 Eric Lippert 最近的博客文章,关于如何存储和管理变量。blogs.msdn.com/b/ericlippert/archive/2010/09/30/......
0赞 leppie 9/29/2008 #2

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

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

2赞 Marc Gravell 9/29/2008 #3

我想我要问的更多问题是它如何使用局部变量 [MG编辑:“哎呀 - 忽略这个......”事后添加]

这就是重点;它真的不再是一个局部变量了——至少,不是我们通常认为它们的方式(在堆栈等上)。它看起来像一个,但事实并非如此。

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