怎么可以预览自己做的网站,学术ppt模板免费,wordpress 文章顶踩插件,官方网站建设报价表前言在公众号上看到一篇文章《正确使用和理解C#中的闭包》#xff0c;里面提到了闭包的一个坑#xff1a;当捕获的外部变量为for循环的迭代变量时#xff0c;C#认为变量i是定义在循环体外的。所以#xff0c;当添加委托集合的for循环执行完时#xff0c;i的值已经变为3了里面提到了闭包的一个坑当捕获的外部变量为for循环的迭代变量时C#认为变量i是定义在循环体外的。所以当添加委托集合的for循环执行完时i的值已经变为3了因此我们在foreach中循环调用委托时i的值就都是3了。ListAction levyActions new ListAction();
for (int i 0; i 3; i)
{levyActions.Add(() i.Dump());
}
foreach (Action action in levyActions)
{action();
}那么明明是循环体内定义的变量i为什么会被认为定义在循环体外呢编译器魔法——Lowering我们知道C#代码最终会编译成IL中间语言。假设有一个数组int[] arr new[] { 0, 1, 2 };我们可以有多种方式遍历它//1
foreach (var i1 in arr)
{i1.Dump();
}
//2
for (var i2 0; i2 arr.Length; i2)
{var value arr[i2];value.Dump();
}
//3
var i3 0;
while(i3 arr.Length)
{var value arr[i3];value.Dump();i3;
}那么是不是要对应准备3种IL语法呢其实不是在编译之前编译器还会施展一个魔法Lowering大概意思是让编译器从高级语言功能“降低”到同一语言中的低级语言功能。怎么理解这句话呢让我们打开https://sharplab.io/Roslyn编译器实现sharplab.io这个网站可以显示.NET代码比如c#的编译中间过程和结果。我们将上面的C#代码复制到窗口左边可以看到编译器会将foreach和for语法都转换成while语法这样编译器最后只需要实现一种IL语法即可。除了迭代以外在roslyn编译器中实现了很多的“Lowering”比如异步重写器Lambda重写器状态机重写器详细列表你可以查看“https://github.com/dotnet/roslyn/tree/main/src/Compilers/CSharp/Portable/Lowering”下的代码。结论现在大家应该已经知道for循环中的变量i实际会被转换成while循环外定义的变量num因此i在循环体作用域外也是有效的导致了闭包的这个坑。知道了原理解决方案也很简单始终使用循环体内的变量即可for (var i 0; i 3; i)
{var j i;levyActions.Add(() j.Dump());
}如果你觉得这篇文章对你有所启发请关注我的个人公众号”My IO“