C#中携带实例变量的Lambda工作原理是什么?
C# 嵌套Lambda与闭包原理解答
1. 嵌套Lambda(adder函数)的运行逻辑
首先看adder的声明:
Func<int, Func<int, int>> adder = (int x) => (int y) => x + y;
Func<int, Func<int, int>> 表示这是一个入参为int、返回值为另一个委托的高阶函数,返回的委托类型是Func<int, int>(入参int、返回int)。
执行逻辑拆分:
- 调用
adder(5)时,参数x被赋值为5,此时返回一个新的委托:(y) => 5 + y,这个返回的委托赋值给add5 - 调用
add5(1)时,参数y被赋值为1,执行5 + 1得到结果6,和断言一致 adder(6)同理返回(y) => 6 + y,赋值给add6,调用add6(-1)得到6 + (-1) = 5
2. x与y的变量属性说明
C#编译器会为捕获了外部变量的Lambda生成隐藏的闭包类:
- x是闭包类的实例字段:当调用adder传入x值时,x会被保存到返回的委托对应的闭包实例中,生命周期和返回的委托绑定,所以后续调用add5、add6时还能拿到当时传入的x值
- y不是实例变量:y是返回的
Func<int, int>委托的入参,每次调用这个委托时才会传入,调用结束就失效,不会被持久化存储
3. 闭包示例的运行原理
闭包的核心特性是Lambda可以捕获其定义作用域内的变量,哪怕该变量的原始作用域已经退出,具体实现逻辑:
int yEnclosed = 1; Func<int, int> addWithClosure = (x) => x + yEnclosed;
编译器检测到Lambda捕获了局部变量yEnclosed后,会自动生成一个隐藏的闭包类:
- 把yEnclosed提升为该闭包类的公共实例字段,而不是方法栈上的局部变量
- 定义Lambda的逻辑作为该闭包类的实例方法
- 实例化这个闭包类,把yEnclosed的初始值1赋值给实例的对应字段
- addWithClosure实际上是指向这个闭包实例方法的委托
所以调用addWithClosure(2)时,实际上是调用闭包实例的方法,读取实例中保存的yEnclosed值1,计算2 + 1 = 3,和断言一致。
额外说明:闭包捕获的是变量的引用而非副本,如果你在Lambda定义后修改yEnclosed的值,后续调用addWithClosure的返回值也会同步变化。
内容的提问来源于stack exchange,提问作者David Thielen
相关产品推荐
相关产品推荐

