gpt4 book ai didi

c# - 如何|封闭变量存储在哪里?

转载 作者:太空狗 更新时间:2023-10-29 18:28:25 25 4
gpt4 key购买 nike

这是一个基于文章 "Closing over the loop variable considered harmful" 的问题埃里克·利珀特 (Eric Lippert)。
这是一本好书,Eric 解释了为什么在这段代码之后所有函数都将返回 v 中的 last 值:

 var funcs = new List<Func<int>>();
foreach (var v in values)
{
funcs.Add(() => v);
}

正确的版本是这样的:

 foreach (var v in values)
{
int v2 = v;
funcs.Add(() => v2);
}

现在我的问题是那些捕获的“v2”变量如何存储以及存储在哪里。在我对堆栈的理解中,所有这些 v2 变量都会占用同一 block 内存。

我的第一个想法是装箱,每个 func 成员都保留对装箱 v2 的引用。但这并不能解释第一种情况。

最佳答案

通常情况下,变量 v2 会在其所在代码块的开头分配一些堆栈空间。在代码块的末尾(即迭代结束)堆栈倒退(我描述的是逻辑场景而不是优化的实际行为)。因此,每个 v2 实际上都是与前一次迭代不同的 v2,尽管它最终会占用相同的内存位置。

然而,编译器发现 v2 正被 lambda 创建的匿名函数使用。编译器所做的是 hoist v2 变量。编译器创建一个新类,它有一个 Int32 字段来保存 v2 的值,它没有在堆栈上分配一个位置。它还使匿名函数成为这种新类型的方法。 (为简单起见,我将给这个未命名的类起一个名字,我们称它为“Thing”)。

现在,在每次 迭代中,都会创建“Thing”的 实例,当v2 被赋值时,它的Int32 字段实际上被赋值了不仅仅是堆栈内存中的一个点。匿名函数表达式(lambda)现在将返回一个具有非空实例对象引用的委托(delegate),该引用将指向“Thing”的当前实例

当调用匿名函数的委托(delegate)时,它将作为“Thing”实例的实例方法执行。因此,v2 可作为成员字段使用,并将在创建“Thing”实例的迭代期间为其提供值。

关于c# - 如何|封闭变量存储在哪里?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/1747726/

25 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com