问题
异步操作时, 需要展示该操作的进度
解决方案
IProgress<T> Interface 和 Progress<T> Class
插一段话: 读《C# 并发编程经典实例》这本书偶有困惑, 深感书中内容过于精炼, 或许是作者故意为之, 但显然对我这般知识浅薄的人来说, 读起来这本书感到晦涩. 偶然找到作者的个人博客, 看到作者博客中对某一个知识点不同时间点上由浅至深的研究, 十分欣喜. 作者个人博客地址: https://blog.stephencleary.com/
可查看此书作者博客文章 Reporting Progress from Async Tasks 了解更多一手知识
文中作者多次提到 UI 线程, 很困惑, 因为最近几年基本没在工作中写 WPF,webForm 或者 WinForm, 所以作者说 UI 线程时很困惑, 将其带入 WPF,WebForm 或者 WinForm 的使用场景, 就好理解了.
不在废话, 上文中伪代码例子
- static async Task MyMethodAsync(IProgress<double> progress = null)
- {
- double percentComplete = 0;
- while (!done)
- {
- ...
- if (progress != null)
- progress.Report(percentComplete);
- }
- }
Progress 只有一个 Report 方法, Report 报告进度更改
- static async Task CallMyMethodAsync()
- {
- var progress = new Progress<double>();
- progress.ProgressChanged += (sender, args) =>
- {
- ...
- };
- await MyMethodAsync(progress);
- }
注意
IProgress<T > 参数可以为空, 这意味着该异步操作不需要报告更改进度.
Report 方法可以是异步的, 这样的话, MyMethodAsync 执行过程中, 可能 Report 方法还未执行, 进度还没有被更新. 这样的话, T 最好是一个不可变类型, 值类型最好, 如果 T 非要使用可变类型, 最好每次 Copy 一个副本.
如果一个方法可以报告进度, 最好也应该可以被取消.
Progress 会在创建时捕获当前上下文, 并且在这个上下文中调用回调函数. 这意味着, 如果在 UI 线程中创建了 Progress , 就能在 Progress 的回调函数中更新 UI, 即使异步方法是在后台线程中调用 Report 的.
关于如何使用进度, 并可以取消该方法的文章, 可查看 4.5 中的异步: 启用进度和异步 API 中的取消
异常
Progress<T>.ProgressChanged 不会抛出异常, 或者说它抛出的异常会直接抛给上下文 context
来源: http://www.bubuko.com/infodetail-2889809.html