根据我所知,当我在C#中定义一个方法时,在完成执行此方法的块[当GC想要]时,此方法中的局部变量将从内存中释放,
但如果我在方法中有内联回调,这些局部变量是否也会从内存中释放出来?
在下面的例子中,[x]变量将在完成执行方法后保持其值,并且消息将显示[x]的值而没有问题,尽管它在回调中!!
private void MyMethod()
{
int x = 1;
System.Timers.Timer t = new System.Timers.Timer(1000);
t.Elapsed += (sender, e) => MessageBox.Show((x++).ToString()); ;
t.Start();
}
答案 0 :(得分:5)
变量x
在与lambda函数关联的闭包中捕获。这意味着x
的值实际上并不存储在与MyMethod
的执行相关联的堆栈上,而是存储在堆上(在从lambda函数引用的对象中)。
以下示例(粗略地)显示了C#编译器如何转换代码:
class $$MyMethod$$Closure {
public int x;
void Function(object sender, EventArgs e) {
MessageBox.Show((x++).ToString());
}
}
private void MyMethod() {
var $$closure = new $$MyMethod$$Closure();
$$closure.x = 1;
System.Timers.Timer t = new System.Timers.Timer(1000);
t.Elapsed += $$closure.LambdaFunction;
t.Start();
}
如您所见,x
变量现在存储在堆分配的对象(称为闭包)中。只要计时器可以调用该方法(并且只要x
可以访问),该对象就会处于活动状态,但是一旦删除了计时器,关闭也将被垃圾收集。
值得注意的是,编译器只捕获 lambda函数中实际使用的那些局部变量(所以如果你在方法中有一些大数据,它们就不会被意外保存比需要的时间长。)