当我在lambda中捕获int
时,我猜它是在堆中分配的,以防止在块的末尾重新分配。
然后,它如何/何时被解除分配?值是否装箱(那么它必须像任何其他参考一样工作)? GC中是否有特殊功能来管理堆上的结构?
答案 0 :(得分:2)
在lambda中捕获局部变量时it becomes a regular field in the compiler-generated lambda class。例如,这个:
static void Main(string[] args) {
int capture = 5;
Func<int, int> func = input => input * capture;
}
可以通过C#编译器降低到:
[CompilerGenerated]
private sealed class <>c__DisplayClass0_0
{
public int capture;
internal int <Main>b__0(int input)
{
return input * this.capture;
}
}
private static void Main(string[] args)
{
new C.<>c__DisplayClass0_0().capture = 5;
}
因此:
然后,如何/何时解除分配?
当类实例被释放时,它就像类实例的常规值类型字段一样被释放。
值是否已装箱(那么它必须像任何其他参考一样工作)?
通常,我们使用装箱来引用隐式表示 - 将值类型转换为特殊引用类型,其唯一的功能是(稍后)启用非表示更改的赋值引用类型位置的原始值(通常为object
类型或实现原始值类型的任何接口类型)。在引擎盖下,拳击是由CLR使用a special IL instruction.
在lambda的上下文中,即使值可能作为类实例的字段进入堆,我们也不会将它称为常规意义上的装箱。在引擎盖下,通过为您编写一些等效的样板代码,捕获变量是C#编译器负责的事情。
当然,正如评论中所指出的那样,最终它们归结为同样的事情:它们在堆上分配一个结构。
GC中是否有特殊功能来管理堆上的结构?
具体而言,lambda捕获没有什么特别之处。 GC已经知道如何释放值类型字段。