在C#的世界里,Lambda表达式以其简洁和匿名性成为了许多开发者喜爱的工具。但正如一把双刃剑,它也可能在不经意间引入一些“隐秘”的陷阱,尤其是当我们试图在Lambda表达式中捕获外部变量时。
让我们先来看一个常见的例子:
List<Action> actions = new List<Action>();
for (int i = 0; i < 10; i++)
{
actions.Add(() => Console.WriteLine(i));
}
foreach (Action a in actions)
{
a();
}
这段代码的目的是创建一个操作列表,每个操作都会打印出一个从0到9的计数器值。然而,令人惊讶的是,它竟然打印了“10”十次!
这是因为Lambda表达式捕获了对循环变量i
的引用,而不是它的值。当循环修改i
时,所有Lambda都看到了最终的值“10”。
要解决这个问题,我们需要改变Lambda表达式捕获变量的方式。一种常见的方法是“按值捕获”。虽然C#没有直接支持按值捕获的语法,但我们可以通过创建本地副本来实现这一点:
for (int i = 0; i < 10; i++)
{
int copy = i; // 创建本地副本
actions.Add(() => Console.WriteLine(copy));
}
现在,每个Lambda都捕获了一个独立的copy
变量,为每次迭代保留了正确的值。
这里的关键在于变量的作用域和生命周期。引用共享相同的内存位置,因此对其中一个引用的更改会立即反映到其他引用上。而当我们创建一个本地副本时,我们实际上是在创建一个变量的独立快照。这意味着对原始变量的后续更改不会影响到已经捕获的副本。
除了按值捕获外,还有一些其他的注意事项:
总的来说,C# Lambda表达式是一种强大而灵活的工具,但也需要谨慎使用以避免“隐秘”的陷阱。通过理解变量捕获的工作原理并采取适当的预防措施,我们可以确保代码的正确性和可维护性。
声明:
1、本博客不从事任何主机及服务器租赁业务,不参与任何交易,也绝非中介。博客内容仅记录博主个人感兴趣的服务器测评结果及一些服务器相关的优惠活动,信息均摘自网络或来自服务商主动提供;所以对本博客提及的内容不作直接、间接、法定、约定的保证,博客内容也不具备任何参考价值及引导作用,访问者需自行甄别。
2、访问本博客请务必遵守有关互联网的相关法律、规定与规则;不能利用本博客所提及的内容从事任何违法、违规操作;否则造成的一切后果由访问者自行承担。
3、未成年人及不能独立承担法律责任的个人及群体请勿访问本博客。
4、一旦您访问本博客,即表示您已经知晓并接受了以上声明通告。
本站资源仅供个人学习交流,请于下载后24小时内删除,不允许用于商业用途,否则法律问题自行承担。
Copyright 2005-2024 yuanmayuan.com 【源码园】 版权所有 备案信息
声明: 本站非腾讯QQ官方网站 所有软件和文章来自互联网 如有异议 请与本站联系 本站为非赢利性网站 不接受任何赞助和广告