Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

C# async/await Progress event on Task<> object

Tags:

c#

async-await

I'm completely new to C# 5's new async/await keywords and I'm interested in the best way to implement a progress event.

Now I'd prefer it if a Progress event was on the Task<> itself. I know I could just put the event in the class that contains the asynchronous method and pass some sort of state object in the event handler, but to me that seems like more of a workaround than a solution. I might also want different tasks to fire off event handlers in different objects, which sounds messy this way.

Is there a way I could do something similar to the following?:

var task = scanner.PerformScanAsync();
task.ProgressUpdate += scanner_ProgressUpdate;
return await task;
like image 790
Connell Avatar asked Mar 14 '13 11:03

Connell


2 Answers

The recommended approach is described in the Task-based Asynchronous Pattern documentation, which gives each asynchronous method its own IProgress<T>:

public async Task PerformScanAsync(IProgress<MyScanProgress> progress) {   ...   if (progress != null)     progress.Report(new MyScanProgress(...)); } 

Usage:

var progress = new Progress<MyScanProgress>(); progress.ProgressChanged += ... PerformScanAsync(progress); 

Notes:

  1. By convention, the progress parameter may be null if the caller doesn't need progress reports, so be sure to check for this in your async method.
  2. Progress reporting is itself asynchronous, so you should create a new instance of your arguments each time you call (even better, just use immutable types for your event args). You should not mutate and then re-use the same arguments object for multiple calls to Progress.
  3. The Progress<T> type will capture the current context (e.g., UI context) on construction and will raise its ProgressChanged event in that context. So you don't have to worry about marshaling back to the UI thread before calling Report.
like image 57
Stephen Cleary Avatar answered Sep 25 '22 03:09

Stephen Cleary


Simply put, Task doesn't support progress. However, there's already a conventional way of doing this, using the IProgress<T> interface. The Task-based Asynchronous Pattern basically suggests overloading your async methods (where it makes sense) to allow clients to pass in an IProgress<T> implementation. Your async method would then report progress via that.

The Windows Runtime (WinRT) API does have progress indicators built-in, in the IAsyncOperationWithProgress<TResult, TProgress> and IAsyncActionWithProgress<TProgress> types... so if you're actually writing for WinRT, those are worth looking into - but read the comments below as well.

like image 42
Jon Skeet Avatar answered Sep 26 '22 03:09

Jon Skeet