【问题标题】:When a variable is closed twice, where is it stored?当一个变量被关闭两次时,它存储在哪里?
【发布时间】:2017-02-15 19:31:13
【问题描述】:

我在阅读这篇名为C# Closures Explained 的文章时很有趣,其中指出:

您会看到,C# 编译器检测到委托何时形成一个从当前范围传递的闭包,并将委托和相关的局部变量提升为编译器生成的类。这样,它只需要一点编译器技巧来传递编译器生成的类的实例,所以每次调用委托时,我们实际上是在调用这个类的方法。

所以本质上,一个封闭的变量被存储为一个匿名类的成员变量,该类还包含代表 lambda 表达式的委托或其他关闭该变量的代码。

如果是这样,当一个方法包含两个不同的 lambda 表达式并且它们都引用同一个局部变量时会发生什么?

void Test(IList list)
{
    int i = 0;

    list.Any( a => { Console.WriteLine("Lambda one says: {0}", i++); return true;} )
        .Any( a => { Console.WriteLine("Lambda two says: {0}", i++); return true;} );

}

我很确定我知道这里的行为。我的问题是,i 到底存储在哪里?

【问题讨论】:

  • FWIW,该代码无法编译。 Any()IEnumerable<T> 的扩展方法,期待 Func<T, bool> 而不是 Action
  • @Cameron 除非他们有自己的 Console 类和自己的返回布尔值的 WriteLine 方法。 (还有他们自己的Any 扩展方法IList,因为LINQ Any 方法不需要IList)。
  • 所有局部变量都存储在执行栈中。
  • @jdweng 这完全是错误的,就像这里显示的代码一样,它甚至包含语言文档的引用形式,解释了本地存储的位置(以及它如何不能在堆)。如果变量需要存储在堆栈中,闭包可能无法工作,因为变量需要在方法完成后存在,如果它存储在堆栈中,则不会发生这种情况。
  • 首先,内存必须在某个地方,并且局部变量放在堆栈上。其次 i 不是 lambda 表达式的一部分,因此语言文档中的引用不适用。

标签: c# .net lambda closures


【解决方案1】:

该方法只有一个闭包类,而不是每个匿名方法一个。 one 类将有两个实例方法和一个字段。该字段将存储i的值,这两个方法将分别对应您的两个匿名方法。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2010-12-17
    • 2021-11-14
    • 1970-01-01
    • 2017-03-26
    • 2010-10-02
    • 2013-11-08
    • 2018-02-01
    相关资源
    最近更新 更多