闭包如何在幕后工作?(C#)

Mat*_*att 45 .net c# closures

我觉得我对闭包有很好的理解,如何使用它们,以及它们什么时候有用.但我不明白的是他们实际上是如何在幕后的幕后工作的.一些示例代码:

public Action Counter()
{
    int count = 0;
    Action counter = () =>
    {
        count++;
    };

    return counter;
}
Run Code Online (Sandbox Code Playgroud)

通常,如果闭包没有捕获{count},它的生命周期将被限定为Counter()方法,并且在它完成之后它将消除Counter()的其余堆栈分配.什么时候关闭会发生什么?这个Counter()调用的整个堆栈分配是否存在?它会将{count}复制到堆中吗?它是否从未真正在堆栈上分配,但被编译器识别为关闭,因此总是存在于堆上?

对于这个特殊的问题,我主要关注它在C#中是如何工作的,但是不反对与支持闭包的其他语言进行比较.

Eri*_*ert 47

你的第三个猜测是正确的.编译器将生成如下代码:

private class Locals
{
  public int count;
  public void Anonymous()
  {
    this.count++;
  }
}

public Action Counter()
{
  Locals locals = new Locals();
  locals.count = 0;
  Action counter = new Action(locals.Anonymous);
  return counter;
}
Run Code Online (Sandbox Code Playgroud)

合理?

另外,您要求进行比较.VB和JScript都以完全相同的方式创建闭包.


Joe*_*orn 33

所述编译器(而不是在运行时)创建另一个类/类型.您的闭包函数以及您关闭/提升/捕获的任何变量将作为该类的成员在您的代码中重写..Net中的闭包实现为此隐藏类的一个实例.

这意味着你的count变量完全是一个不同类的成员,并且该类的生命周期与任何其他clr对象一样.在它不再生根之前,它不符合垃圾收集的条件.这意味着只要你有一个可调用的方法引用它就不会去任何地方.

  • ...只需在解决方案中查找最丑陋的命名类. (5认同)
  • 使用Reflector检查有问题的代码以查看此示例 (4认同)
  • 这是否意味着闭包将导致新的堆分配,即使被关闭的值是原始的? (2认同)