【发布时间】:2017-09-05 21:31:40
【问题描述】:
我试过这段代码
struct Bar {
public int Value;
}
async Task doItLater(Action fn) {
await Task.Delay(100);
fn();
}
void Main() {
Bar bar = new Bar { Value = 1 }; //Bar is a struct
doItLater(() => {
Console.WriteLine(bar.Value);
}).Wait();
}
并得到输出1。现在这让我很困惑。我的逻辑如下
- Bar 是一个结构。因此所有实例都应该存储在堆栈中
- 当
Task.Delay(100)被命中时,执行线程完成,并请求TPL 稍后执行fn()。 -
bar存储在堆栈中,当我们在闭包中访问它时,该帧不应该存在。
那么我到底是怎么得到1的输出的呢?
【问题讨论】:
-
And therefore all instances should be stored on the stack这是一个不正确的假设,因此由此得出的结论并不可靠。bar is stored on the stack也是虚假陈述。 -
使用反编译器,如 Redgate Reflector 或 dotPeek 或 ILSpy,看看它的神奇之处。真的没那么复杂。
-
bar存储在堆上,因为它参与了 closure,因为它是引用它的匿名函数。如果它没有将其存储在闭包中,则值bar将在Main退出时从内存中删除,这将对您的匿名函数造成严重问题。 -
@Servy 我认为
structs 的实例存储在堆栈中?这不总是正确的吗?这是真的吗? -
一个简单的事实是,你看这个完全错误的方式。正确的思考方式是变量是存储,并且已知存储的寿命不超过方法激活,或者可能比方法激活的寿命更长。已知具有短生命周期的变量可以进入 短生命周期池,也称为“堆栈”。所有其他变量都必须放在堆上。不管变量是持有一个 int 还是对一个字符串的引用,这都是正确的。