You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

为何添加防越界条件仍出现C#数组索引越界异常?

闭包捕获引发的Task索引越界问题分析与解决

问题根源

你的代码里的Task.Run使用lambda表达式捕获了idplayer变量,但闭包捕获的是变量的引用,而非循环迭代时的变量值:

  • 循环的执行速度远快于后台Task的启动和执行逻辑,当Task真正开始调用Updateplayer(players[idplayer])时,循环已经把idplayer的值递增到了超出players.Count的范围。
  • 虽然while循环条件检查了idplayer < players.Count,但这只是在循环迭代的瞬间生效,Task的异步执行不会等待循环步完成再运行,因此后续Task执行时,idplayer的值可能已经超出了合法索引范围。

解决方案

方式一:循环内创建局部变量保存当前索引值

每次迭代时把idplayer的当前值赋值给一个局部变量,让lambda捕获这个局部变量(每个迭代的局部变量是独立的,不会被后续循环修改):

Task[] lestasks = new Task[5];
 
int idplayer = 0;
int numtask = 0;

while (numtask < 5 && idplayer < players.Count)
{
    // 保存当前迭代的索引值到局部变量
    int currentId = idplayer;
    lestasks[numtask] = Task.Run(() => { Updateplayer(players[currentId]); });

    numtask++;
    idplayer++;
}

Task.WaitAll(lestasks);

方式二:改用foreach循环(C# 5及以上版本)

C# 5及之后的foreach会为每个迭代创建独立的变量,自动避免闭包捕获的陷阱,代码更简洁:

var lestasks = new List<Task>();
int numtask = 0;

foreach (var player in players)
{
    if (numtask >= 5) break;
    lestasks.Add(Task.Run(() => { Updateplayer(player); }));
    numtask++;
}

Task.WaitAll(lestasks.ToArray());

额外注意

原代码中lestasks是固定长度为5的数组,如果players.Count小于5,数组中未赋值的元素会是null,调用Task.WaitAll时会抛出异常。建议改用List<Task>动态添加任务,避免空Task的问题。

内容的提问来源于stack exchange,提问作者UserNam3

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.15 08:12:36