匿名方法捕获变量:
static MethodInvoker CreateDelegateInstance( ){
int counter = 5;
MethodInvoker ret = delegate{
Console.WriteLine( counter );
counter++;}
ret();
return ret;
}
MethodInvoker x = CreateDelegateInstance();
x();
x();
这里匿名方法捕获了变量 counter, 编译器会创建一个额外的类来容纳变量,CreateDelegateInstance 方法拥有对该类的一个实例引用,并且委托也有该实例的一个引用。
这个实例和其他实例一样也被保存在堆上,除非委托准备好呗垃圾回收,否则那个实例不会被回收的。
如果只捕捉this,就不需要额外的类型,编译器将直接创建一个实例方法来作为委托的操作。
对于一个捕获变量,只要还有任何委托实例在引用它,它就会一直存在。
局部变量所需的全部空间都在方法开始时的栈上分配。因此下面的代码不会产生每次循环迭代都“重新声明”变量的开销。
(如果是局部对象,也是栈上保存局部对象,然后局部对象指向一个堆上的空间)
int single;
for( int i=0; i<10; ++i )
{
single = 5;
Console.WriteLine( single +i );
}
for (int i = 0; i < 10; ++i)
{
int multiple = 5;
Console.WriteLine(multiple+i);
}
但是,一旦如果使用了变量捕获,那么循环内的变量将实例化多次,每次循环迭代时捕获的变量是不同的。
MethodInvoker[] delegates = new MethodInvoker[2];
for (int i = 0; i < 2; ++i)
{
int multiple = 5;
delegates[i] = delegate
{
multiple++;
Console.WriteLine( "multiple: {0}", multiple );
};
}
delegates[0]();//输出6
delegates[1]();//输出6