我对 C# 5 的新 async
完全陌生/await
关键字,我对实现进度事件的最佳方式很感兴趣。
现在我更喜欢 Progress
事件发生在 Task<>
本身。我知道我可以将事件放在包含异步方法的类中并在事件处理程序中传递某种状态对象,但对我来说这更像是一种变通方法而不是解决方案。我可能还希望不同的任务触发不同对象中的事件处理程序,这样听起来很困惑。
有什么办法可以做类似下面的事情吗?:
var task = scanner.PerformScanAsync();
task.ProgressUpdate += scanner_ProgressUpdate;
return await task;
最佳答案
推荐的方法在 Task-based Asynchronous Pattern 中有描述。文档,它为每个异步方法提供了自己的 IProgress<T>
:
public async Task PerformScanAsync(IProgress<MyScanProgress> progress)
{
...
if (progress != null)
progress.Report(new MyScanProgress(...));
}
用法:
var progress = new Progress<MyScanProgress>();
progress.ProgressChanged += ...
PerformScanAsync(progress);
注意事项:
- 按照惯例,
progress
参数可能是null
如果来电者不需要进度报告,那么请务必在您的async
中检查这一点方法。 - 进度报告本身是异步的,因此您应该在每次调用时创建一个新的参数实例(更好的是,只需为您的事件参数使用不可变类型)。您应该不改变并重新使用相同的参数对象多次调用
Progress
. Progress<T>
type 将在构造时捕获当前上下文(例如,UI 上下文)并将提高其ProgressChanged
在这种情况下发生的事件。因此,您不必担心在调用Report
之前编码(marshal)回 UI 线程。 .
关于Task<> 对象上的 C# async/await Progress 事件,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/15408148/