C# Lambda表达式中int变量按值还是按引用捕获?程序行为答疑
解释C# Lambda捕获局部变量的行为
先明确这个程序的运行结果:
- 执行
fun1()时,调用委托a后,局部变量x的值变为4; - 执行
fun2()时,再次调用委托a,修改的是同一个x(此时值变为5)。
核心问题解答
你的疑惑点在于“为什么Lambda捕获的fun1局部变量x,能在fun1执行完后还能被fun2里的委托访问”,本质是C#编译器对Lambda捕获局部变量的特殊处理:
Lambda并没有直接捕获栈上的局部变量引用:当Lambda捕获值类型的局部变量时,编译器会自动生成一个隐藏的匿名类,把被捕获的局部变量
x包装成这个类的实例字段。Lambda表达式本身会持有这个匿名类实例的引用,所有对x的操作,实际都是操作这个类实例里的字段。匿名类实例的生命周期不受fun1栈帧限制:fun1执行完毕后,栈上的局部变量(原
x)会被销毁,但堆上的匿名类实例因为被静态委托a持有引用,不会被GC回收。所以在fun2中调用a时,依然能访问并修改这个实例里的x字段。
程序执行的详细流程
fun1执行时,初始化局部变量x=3,编译器将x包装进一个匿名类的实例中;- 赋值
a = () => { ++x; };,此时委托a指向这个匿名类实例的方法,操作的是实例内的x字段; - 调用
a(),实例内的x自增为4,此时int b = x实际是读取实例字段的值,所以b=4; fun1执行完毕,栈帧销毁,但匿名类实例因被静态委托a引用,保留在堆上;fun2调用a(),再次对实例内的x自增,此时x变为5。
内容的提问来源于stack exchange,提问作者alangab
相关产品推荐
相关产品推荐

