反编译分析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开销。

相关推荐
似水明俊德3 小时前
02-C#.Net-反射-面试题
开发语言·面试·职场和发展·c#·.net
阿蒙Amon4 小时前
C#常用类库-详解SerialPort
开发语言·c#
似水明俊德6 小时前
02-C#.Net-反射-学习笔记
开发语言·笔记·学习·c#·.net
.NET修仙日记11 小时前
Acme.ReturnOh:让.NET API返回值处理更优雅,统一响应格式一步到位
c#·.net·webapi
阿蒙Amon13 小时前
C#常用类库-详解YamlDotNet
开发语言·c#
Sunsets_Red15 小时前
乘法逆元的 exgcd 求法
c++·学习·数学·算法·c#·密码学·信息学竞赛
唐青枫16 小时前
深入理解 C#.NET TaskScheduler:为什么大量使用 Work-Stealing
c#·.net
人工智能AI技术16 小时前
Claude 3.7 企业版私有化部署技术验证:与 .NET 实战方案
人工智能·c#
呆子也有梦16 小时前
思考篇:积分是存成道具还是直接存数值?——ET/Skynet 框架下,从架构权衡到代码实现全解析
游戏·架构·c#·lua
我是唐青枫17 小时前
深入理解 C#.NET Task.Run:调度原理、线程池机制与性能优化
性能优化·c#·.net