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

WinForms异步方法在foreach中提前迭代的原因咨询

问题分析与解决方案

嗨,我来帮你搞明白这个问题~

你遇到的核心问题,根源在于**async void方法的特性**。虽然你在GetInfoAsync里用了await,但因为这个方法是async void类型,当你在foreach循环里调用它时,调用方(循环)根本没办法等待它执行完成。

具体原因

当GetInfoAsync执行到await Task.Run(...)这一行时,它会立即把控制权交还给调用它的foreach循环,自己进入等待状态。这时候循环就直接跳到下一次迭代,不会等这个方法里的异步操作完成——这就是为什么你觉得“foreach没等GetInfoAsync做完就跑下一轮”的原因。

async void其实是专门为事件处理程序设计的(比如你的按钮点击方法GetInfoToolStripMenuItem_Click用async void是合理的),但普通的异步工作方法,我们应该用async Task作为返回类型,这样调用者才能等待它完成。

修复步骤

1. 把GetInfoAsync改成async Task返回类型

private async Task GetInfoAsync(DataGridViewRow row) { 
    Server server = (Server)row.Cells[0].Value; 
    row.Cells[1].Value = Resources.GettingIcon; 
    await Task.Run(() => { 
        server.Data = dataGetter.GetData(server); 
    }); 
    row.Cells[1].Value = Resources.FinishedIcon; 
}

2. 修改按钮点击事件,根据需求选择并行或串行处理

如果你想同时获取所有服务器的数据(效率更高,推荐),用Task.WhenAll来等待所有任务完成:

private async void GetInfoToolStripMenuItem_Click(object sender, EventArgs e) { 
    var tasks = new List<Task>();
    foreach (DataGridViewRow row in infoDataGridView.Rows) 
        tasks.Add(GetInfoAsync(row));
    // 等待所有异步任务都完成
    await Task.WhenAll(tasks);
}

如果你想一个接一个地获取数据(串行执行),直接在循环里await每个GetInfoAsync调用:

private async void GetInfoToolStripMenuItem_Click(object sender, EventArgs e) { 
    foreach (DataGridViewRow row in infoDataGridView.Rows) 
        // 等当前服务器的数据获取完成,再处理下一个
        await GetInfoAsync(row); 
}

额外提醒

async void还有个坑:如果方法里抛出异常,很难被捕获到。换成async Task后,你可以通过try/catch包裹await来处理异常,让程序更健壮。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.05.15 03:17:34