闭包中变量捕获详解
我看过无数关于变量捕获如何引入变量来创建闭包的帖子,但是它们似乎都缺乏具体细节,并将整个事情称为“编译器魔法”。
我正在寻找以下内容的明确解释:
- 局部变量实际上是如何捕获的。
- 捕获值类型与引用类型之间的差异(如果有)。
- 以及值类型是否发生装箱。
我更喜欢从值和指针方面得到答案(更接近内部发生的事情的核心),尽管我也会接受涉及值和引用的明确答案。
I've seen countless posts on how variable capture pulls in variables for the creation of the closure, however they all seem to stop short of specific details and call the whole thing "compiler magic".
I'm looking for a clear-cut explanation of:
- How local variables are actually captured.
- The difference (if any) between capturing value types vs. reference types.
- And whether there is any boxing occurring with respect to value types.
My preference would be for an answer in terms of values and pointers (closer to the heart of what happens internally), though I will accept a clear answer involving values and references as well.
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(1)
通过示例演示捕获的工作原理可能是最简单的...
下面是一些使用 lambda 表达式捕获单个变量的代码:
现在这就是编译器为您所做的事情 - 除了它会使用“无法形容的”名称确实发生在C#中。
如果捕获在循环中声明的变量,则每次循环迭代都会得到一个新的 ActionHelper 实例 - 因此您可以有效地捕获变量的不同“实例”。
当您从不同范围捕获变量时,它会变得更加复杂...让我知道您是否真的想要这种级别的详细信息,或者您可以编写一些代码,在 Reflector 中反编译它并遵循它:)
注意如何:
编辑:这是两个委托共享变量的示例。一个委托显示
counter
的当前值,另一个委托将其递增:...以及扩展:
It's probably easiest to demonstrate how the capturing works via an example...
Here's some code using a lambda expression which captures a single variable:
Now here's what the compiler's doing for you - except that it would use "unspeakable" names which couldn't really occur in C#.
If you capture variables declared in a loop, you'd end up with a new instance of
ActionHelper
for each iteration of the loop - so you'd effectively capture different "instances" of the variables.It gets more complicated when you capture variables from different scopes... let me know if you really want that sort of level of detail, or you could just write some code, decompile it in Reflector and follow it through :)
Note how:
EDIT: Here's an example of two delegates sharing a variable. One delegate shows the current value of
counter
, the other increments it:... and the expansion: