例子
先看两个典型的使用闭包例子,并思考其输出不同的原因
1 | Action[] actions = new Action[3]; |
1 | Action[] actions = new Action[3]; |
总结
闭包捕获外部变量时是使用引用的方式,所以当闭包执行时,捕获变量将以最新值参与运算
因此,当使用闭包并需要捕获外部变量时,需要思考:
闭包执行的时机与捕获变量的变化之间的关系
闭包的生命周期与捕获变量的生命周期,需要明确只要有任何一个闭包的委托实例在引用捕获变量,它就不会被回收
进阶
其实当闭包需要捕获外部变量时,编译器会生成一个临时类,并以该临时类的实例来持有对外部变量的引用;而当无需捕获外部变量时,不会生成临时类(可反编译深入了解)
所以,有时在考虑程序性能时,也可以考虑避免闭包捕获外部变量:
在设计闭包时,可考虑添加一个或多个可选的范型参数,以适配各种需要传入外部变量的调用,如:
1
2
3public delegate TResult Func<T, TResult>(T arg1);
public delegate TResult Func<T1, T2, TResult>(T1 arg1, T2 arg2);当使用需要传入闭包的方法,并且闭包需要捕获外部变量时,可留意是否还有其他可传参形式的方法可用,如:
UniRx
中的各种xxxWithState()
方法就是为了避免闭包捕获