.NET 匿名函数引用局部变量导致的问题

本文探讨了在.NET环境中,匿名函数引用局部变量可能导致的数组下标越界问题。当在非UI线程操作UI元素如ListView时,使用跨线程调用并遇到此类异常。原因是C#的闭包环境不复制局部变量,而是保留对原始变量的引用。解决方案包括改用Invoke确保同步执行,以及通过创建副本避免变量冲突。
摘要由CSDN通过智能技术生成

问题

写C#窗口程序,今天遇到的问题。在工作线程(非UI线程)要操作ListView,因此使用了跨线程调用方式。

for (int i = 0; i < videos.Count; ++i)
{
    this.BeginInvoke(new Action(() =>
    {
        var item = lvwVideos.FindItemWithText(videos[i]);
        if (item != null)
            lvwVideos.Items.Remove(item);
    }));
}

代码一跑给我抛出了异常,数组下标越界。原因分析如下。

 

分析

C#的闭包环境并不会复制用到的局部变量。

.NET对闭包的实现是在编译阶段而不是运行阶段,事实上,匿名函数中的变量 i 和 for 循环中的i就是同一个变量,由于函数返回后变量还会被匿名函数使用,它会保存在堆中而不是调用栈——不管这个变量是值类型还是引用类型(如果是引用类型即对象和对象的引用都在堆中)。

因此,循环结束后 i 的值已经超出数组 videos 的下标范围。而BeginInvoke函数是不等待执行完毕的,因此很可能循环结束而匿名函数还没有执行完毕。这时匿名函数从堆中取到的 i 已经不是定义匿名函数时 i 的值了。

 

用下面的代码来说可能更清晰。

static void Main(string[] args)
{
    int i 
  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值