带委托的局部变量

Posted

技术标签:

【中文标题】带委托的局部变量【英文标题】:Local variables with Delegates 【发布时间】:2010-09-14 00:03:40 【问题描述】:

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

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

[编辑]:给定一些cmets,把原句改一些……

【问题讨论】:

这种做法没有错。它只是比初学者理解的更高级。 借调;事实上,它可以实现非常干净/优雅的设计 - 但您确实需要了解其中的含义。 这真的很有趣。我不认为在分配委托的范围内弄乱局部变量是一种好习惯,但你总是会学到新的东西。 视场景而定;在大多数情况下,创建第二个范围紧密且永不更改的变量会是一个更好的主意 - 但是有一些更新捕获变量的用例,但确实:将它们视为只读,直到有一个好的原因,你的痛苦就会少得多。 这就是委托和闭包的区别。你在这里所做的是一个闭包。它们非常强大,而且我们在 .NET 中使用闭包这一事实是一个巨大的优势,而不是一个劣势。 【参考方案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# in Depth 中对此进行了很好的描述,并在here 进行了单独(不那么详细)的讨论。

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

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

【讨论】:

除了用 C# 深入编写它(感谢插件!),我还有一篇文章比较了 C# 和 Java 闭包并解释了它们的优点:csharpindepth.com/Articles/Chapter5/Closures.aspx跨度> 啊 - 当你写那条评论时,我正在编辑上面的内容以包含它。双倍的价值;-p @Mark:为了稍微提高你的好答案,你能在最后一句话中用“变量的”交换“变量”吗?由于变量被称为“currentValue”,它可能会使读者(像我一样)感到困惑,首先认为斜体“value”是指变量的name(“变量?那个叫做 value ") 我推荐 Eric Lippert 最近的博客文章,关于如何存储和管理变量。 blogs.msdn.com/b/ericlippert/archive/2010/09/30/…【参考方案2】:

我想我要问的更多问题是它如何与局部变量一起工作 [MG 编辑:“Ack - 忽略这个...”是后来添加的]

这就是重点;它真的不再是一个局部变量了——至少,不是按照我们通常对它们的看法(在堆栈上等)。它看起来像一个,但实际上不是。

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

【讨论】:

【参考方案3】:

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

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

【讨论】:

以上是关于带委托的局部变量的主要内容,如果未能解决你的问题,请参考以下文章

Java 虚拟机原理Class 字节码二进制文件分析 七 ( 局部变量表分析 )

Kotlin 委托

Golang✔️走进 Go 语言✔️ 第九课 局部变量 vs 全局变量

Golang✔️走进 Go 语言✔️ 第九课 局部变量 vs 全局变量

js作用域链以及全局变量和局部变量

java22