You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

闭包的编译器生成代码解析:测试类与自动生成辅助类分析

闭包背后的编译器生成代码解析

嘿,咱们来一步步拆解这段C#闭包代码里编译器偷偷做的工作,搞清楚为什么那个局部变量x能一直保持状态~

先回顾原代码的核心行为

你写的CreateAdder方法里,局部变量x本来是方法栈上的临时变量,按道理CreateAdder执行完就该被销毁了。但因为匿名委托捕获了它,所以它的生命周期被延长了——每次调用返回的Adder委托,都会让x自增并返回最新值,三次调用输出1、2、3,这就是闭包的魔力。

编译器生成的辅助类到底是干啥的?

编译器自动生成的<>c__DisplayClass0_0类(带<>`的命名是编译器专属,避免和你的代码重名),核心作用就是把栈上的局部变量包装成引用类型的成员,具体细节:

  • [CompilerGenerated]标记明确告诉我们这是编译器造的类,不是你写的
  • sealed修饰符是为了让编译器做更多优化(毕竟不需要继承这个类)
  • 里面的public int x就是原代码里的局部变量x——因为值类型的局部变量在栈上,方法结束就没了,编译器把它移到这个类里,变成引用类型的实例成员,这样委托就能通过持有类的实例来持续访问它

匿名方法的转化

原代码里的匿名方法delegate { x++; return x; },编译器会在这个辅助类里生成一个对应的方法,比如命名为<CreateAdder>b__0(你看到的internal...就是这个方法)。这个方法的逻辑很简单:拿到当前辅助类实例的x,自增后返回,伪代码大概是这样:

internal int <CreateAdder>b__0()
{
    this.x++;
    return this.x;
}

CreateAdder方法的实际执行逻辑

编译器会把你写的CreateAdder重写成类似这样的逻辑:

static Adder CreateAdder()
{
    // 创建辅助类的实例
    <>c__DisplayClass0_0 displayClass = new <>c__DisplayClass0_0();
    // 初始化原来的局部变量x
    displayClass.x = 0;
    // 返回绑定了辅助类实例和生成方法的委托
    return new Adder(displayClass.<CreateAdder>b__0);
}

为什么三次调用会输出1、2、3?

当你在Test方法里调用CreateAdder()时,会得到一个绑定了同一个辅助类实例的委托。每次调用add(),本质都是调用这个实例上的<CreateAdder>b__0方法,操作的是同一个x成员,所以每次自增都会保留状态,输出自然是1、2、3。

内容的提问来源于stack exchange,提问作者BennoDual

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.05.25 06:40:43