C# Progress 方法在 await returns 之后执行

C# Progress method executes after the await returns

我第一次尝试异步等待,运行我遇到了使用 Progress 的问题。我使用 await 调用我的异步方法并传入我的进度操作。我想要发生的是显示进度,并且当方法完成时显示消息说我们 "Done!"。发生的事情是显示进度,显示 "Done!" 然后是最后一条进度消息,这是输出示例: 1、 2,

完成! 3

似乎异步已返回并且 UI 上下文在最终 Progress 有机会 运行 之前执行。我可以通过添加处理程序来克服这个问题,但要正确地遵循模式。

 public async void button1_Click(object sender, EventArgs e)
    {
        await JustDoItAsync(new Progress<int>(ProgressUpdate));

        textBox1.Text += "\r\nDone!\r\n";
    }

    public async Task JustDoItAsync(IProgress<int> progress)
    {
        for (int i = 0; i < 3; i++)
        {
            await Task.Delay(500);
            progress.Report(i + 1);
        }
    }

    private void ProgressUpdate(int step)
    {
        textBox1.Text += step + "\r\n";
    }

不幸的是,这种行为并不意外。进度更新是排队的,可以在工作完成后到达。另一方面,任务完成是同步的(假设兼容上下文)。

在这种情况下,由于您使用的是 IProgress<T>,因此您的 JustDoItAsync 永远不需要直接访问 UI。因此,您应该能够在该方法中的 await 上使用 ConfigureAwait(false),这应该会处理好它。

或者,您可以保留 "flag",在任务完成时设置它,并在您的进度报告中检查它,但这会使代码相当笨拙:

public async void button1_Click(object sender, EventArgs e)
{
  Action<int> progressUpdate = ProgressUpdate;
  await JustDoItAsync(new Progress<int>(update => progressUpdate?.Invoke(update)));
  progressUpdate = null;
  textBox1.Text += "\r\nDone!\r\n";
}

另一种选择是在您的 IProgress<T> 实现中嵌入标志。