反编译分析C#闭包

一、问题描述:

比如有这样的代码:

它的输出结果是 3,3,3。

通过搜索得知这一现象是因为C#闭包导致的.

我们借助ILSpy看下IL中间代码,首先它生成了一个名叫DisplayClass的类,类中定义了i的字段

主代码:

在for循环外,定义了DisplayClass的实例,并且对DisplayClass.i进行赋值

其次看下i++实现,是针对DisplayClass.i进行了自增操作。

我们可以对这段代码再进行AI翻译,所以最终执行输出的a.i是最新值3

cs 复制代码
var actions = new List<Action>(); 
DisplayClass a=new DisplayClass();
a.i=0;
while(a.i<3){
    actions.Add(() => Console.WriteLine(a.i));
    a.i=a.i+1;
}

二、解决方式

解决闭包也很简单,就是用局部变量进行赋值

我们再反编译分析下原理

它是在for循环里面生成的DisplayClass的实例,相当于每循环一次都会生成一次实例,那么匿名函数持有的是局部变量DisplayClass实例,所以就能输出正确的值。

总结:

匿名函数引用外部变量i,会在定义变量i的时候实例化一个DisplayClass类,类中声明了i的字段。

1.如果是引用的循环体外的变量,那么每个匿名函数都持有的同一个DisplayClass实例,会导致输出的结果都是最新的值。

2.如果是引用的循环体内的变量,那么每个匿名函数都持有与之对应的DisplayClass实例,能保证值输出正确,但也会带来相应的GC开销。

相关推荐
地球驾驶员2 小时前
NX二次开发C#----C#和C++的二次开发程序如何签名?
c#
小码编匠3 小时前
C# 实现网络文件传输:打造稳定可靠的工业级工具
后端·c#·.net
MM_MS3 小时前
SQL Server数据库和Visual Studio (C#)联合编程
开发语言·数据库·sqlserver·c#·visual studio
c#上位机6 小时前
halcon计算区域骨架
图像处理·人工智能·计算机视觉·c#·halcon
曹牧7 小时前
C#:Dictionary类型数组
java·开发语言·c#
GeekyGuru8 小时前
C#:游戏开发的高效利器
开发语言·c#
关关长语9 小时前
基于NCrontab实现Covarel扩展秒级任务调度
c#·.net
足球中国9 小时前
什么情况下会发生跨域
c#·dataexcel·cfucion
yue00810 小时前
C# 实现电脑锁屏功能
开发语言·c#·电脑·电脑锁屏
2501_9307077810 小时前
如何在 C# 中分离饼图的某个区域
开发语言·c#