meJ*_*rew 0 c# boxing closures
在我问这个问题并阅读这篇关于闭包的推荐文章之后,我开始问自己,如果在C#中进行封闭涉及拳击.
正如文章中所说,这行代码将通过myVar在其范围之外存在来创建闭包:
public static Func<int,int> GetAFunc()
{
var myVar = 1;
Func<int, int> inc = delegate(int var1)
{
myVar = myVar + 1;
return var1 + myVar;
};
return inc;
}
Run Code Online (Sandbox Code Playgroud)
正如那里所解释的,编译器生成的类的对象被实例化以在该范围之外携带该变量的值.这是我的问题:由于变量确实位于堆栈上,使其成为对象的一部分,并不意味着闭包涉及拳击?
由于变量确实位于堆栈上,使其成为对象的一部分,并不意味着闭包涉及拳击?
该句中的错误数量很大.让我们消除一些神话.
(1)值类型的变量不会"进入堆栈". 生命周期较短的变量会进入堆栈.这个变量的寿命很短吗?不,它具有任意长的寿命.它是如何进入堆栈的?没有.
(2)引用类型的对象的字段不在堆栈上.它在堆上.为什么?因为,一个领域具有任意长的寿命.
(3)堆上变量中的整数不需要加框.整数是否加箱取决于整数是否已转换为引用类型.变量的位置无关紧要; 重要的是变量的类型是引用类型还是值类型.
那么让我们来看看你的代码:
public static Func<int,int> GetAFunc()
{
var myVar = 1;
Func<int, int> inc = delegate(int var1)
{
myVar = myVar + 1;
return var1 + myVar;
};
return inc;
}
Run Code Online (Sandbox Code Playgroud)
这段代码是等效的:
private class Closure
{
public int myVar;
public int SomeFunction (int var1)
{
this.myVar = this.myVar + 1;
return var1 + this.myVar;
}
}
public static Func<int,int> GetAFunc()
{
Closure locals = new Closure();
locals.myVar = 1;
Func<int, int> inc = locals.SomeFunction;
return inc;
}
Run Code Online (Sandbox Code Playgroud)
当整数转换为引用类型时,有没有时间?不,所以,没有拳击.
但是要记住,避免装箱的重点是避免分配额外物品的成本.我们确实分配了一个额外的对象:关闭!这里没有拳击惩罚,但由于关闭而有罚款.分配封闭物会增加收集压力.当然,所有对本地的引用现在必须经过额外的间接.