匿名方法捕获变量:

    1. static MethodInvoker CreateDelegateInstance( ){
    2. int counter = 5;
    3. MethodInvoker ret = delegate{
    4. Console.WriteLine( counter );
    5. counter++;}
    6. ret();
    7. return ret;
    8. }
    9. MethodInvoker x = CreateDelegateInstance();
    10. x();
    11. x();

    这里匿名方法捕获了变量 counter, 编译器会创建一个额外的类来容纳变量,CreateDelegateInstance 方法拥有对该类的一个实例引用,并且委托也有该实例的一个引用。
    这个实例和其他实例一样也被保存在堆上,除非委托准备好呗垃圾回收,否则那个实例不会被回收的。
    如果只捕捉this,就不需要额外的类型,编译器将直接创建一个实例方法来作为委托的操作。

    对于一个捕获变量,只要还有任何委托实例在引用它,它就会一直存在。

    局部变量所需的全部空间都在方法开始时的栈上分配。因此下面的代码不会产生每次循环迭代都“重新声明”变量的开销。
    (如果是局部对象,也是栈上保存局部对象,然后局部对象指向一个堆上的空间)

    1. int single;
    2. for( int i=0; i<10; ++i )
    3. {
    4. single = 5;
    5. Console.WriteLine( single +i );
    6. }
    7. for (int i = 0; i < 10; ++i)
    8. {
    9. int multiple = 5;
    10. Console.WriteLine(multiple+i);
    11. }

    但是,一旦如果使用了变量捕获,那么循环内的变量将实例化多次,每次循环迭代时捕获的变量是不同的。

    1. MethodInvoker[] delegates = new MethodInvoker[2];
    2. for (int i = 0; i < 2; ++i)
    3. {
    4. int multiple = 5;
    5. delegates[i] = delegate
    6. {
    7. multiple++;
    8. Console.WriteLine( "multiple: {0}", multiple );
    9. };
    10. }
    11. delegates[0]();//输出6
    12. delegates[1]();//输出6