C#精要 - 小概念篇
闭包
闭包的概念
内层的函数可以引用包含在它外层的函数的变量,即使外层函数的执行已经终止。但该变量提供的值并非变量创建时的值,而是在外部新建一个对象再把对象的引用传给内层函数。
使用闭包
比如在winform想实现:当用户关闭窗体时,给用户一个提示框。
1 | private void Form1_Load(object sender, EventArgs e) |
闭包陷阱
因为内层函数取得的外层函数是其“在父函数范围内(看闭包实现可以知道这不准确)”的最终值,所以遇到需要变动的值(比如循环变量)很容易写错代码。
比如说你想输出1-100的数字:
1 | for (int i = 0; i < 100; i++) |
你会发现和你想做的事,根本不一样,这就是闭包陷阱!正确的做法是使用临时变量保存:
1 | for (int i = 0; i < 100; i++) |
虽然还是利用了闭包特性,但是临时变量j的最终值是1-100的100个数字!
闭包实现
通过反编译再精简代码,看看C#编译器帮我们做了什么。
1 | void Main() |
原来只是帮我们新建了一个类,然后在循环内部大家共用一个对象!
但是只是共用一个对象,为什么输出全是100?线程输出的时候,又不一定是100啊。确实是这样,当我将循环次数改到10000(或者在循环中加入Delay)的时候,发现结果不一样了,输出了好多10000以外的数字。
1 | for (int i = 0; i < 10000; i++) |
所以只是循环的太快了而已!确实跟反编译的结果一致,是共用一个对象,而不是父函数范围内的最终值。
最后再来看一下加了临时变量后的反编译结果:
1 | void Main() |
嗯,优化的跟前面结构完全不一样了,使用临时变量后,现在是大家不共用一个对象了。
本博客所有文章除特别声明外,均采用 CC BY-NC-SA 4.0 许可协议。转载请注明来自 CodingCodingK Blog!