匿名方法捕获变量:
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]();//输出6delegates[1]();//输出6
