• 异步操作执行的过程中,如果需要展示操作的进度,可以考虑使用IProgress<T>Progress<T>
    1. static async Task CallMyMethodAsync()
    2. {
    3. var progress = new Progress<double>();
    4. progress.ProgressChanged += (sender, args) =>
    5. {
    6. Console.WriteLine($"当前进度:{args}%");
    7. };
    8. await MyMethodAsync(progress);
    9. }
    10. static async Task MyMethodAsync(IProgress<double> progress = null)
    11. {
    12. double percentComplete = 0;
    13. while (percentComplete < 100)
    14. {
    15. await Task.Delay(100);
    16. percentComplete++;
    17. if (progress != null)
    18. progress.Report(percentComplete);
    19. }
    20. }

    按照惯例,如果不需要报告进度,IProgress<T> 参数可以是 null,因此在 async 方法中一定要对此进行检查。

    需要注意的是,IProgress<T>.Report 方法可以是异步的。这意味着真正报告进度之前,MyMethodAsync 方法会继续运行。

    基于这个原因,最好把 T 定义为一个不可变类型,或者至少是值类型。如果 T 是一个可变的引用类型,就必须在每次调用 IProgress<T>.Report 时,创建一个单独的副本。

    Progress<T> 会在创建时捕获当前上下文,并且在这个上下文中调用回调函数。这意味着,如果在 UI 线程中创建了 Progress<T>,就能在 Progress<T> 的回调函数中更新 UI,

    即使异步方法是在后台线程中调用 Report 的。