The lack of non-capturing Task.Yield forces me to use Task.Run, why follow that?

You don’t have to put the Task.Run in DoWorkAsync. Consider this option:

public async Task UIAction()
{
    // UI Thread
    Log("UIAction");

    // start the CPU-bound work
    var cts = new CancellationTokenSource(5000);
    var workTask = Task.Run(() => DoWorkAsync(cts.Token)); 

    // possibly await for some IO-bound work 
    await Task.Delay(1000);
    Log("after Task.Delay");

    // finally, get the result of the CPU-bound work
    int c = await workTask;
    Log("Result: {0}", c);
}

This results in code with much clearer intent. DoWorkAsync is a naturally synchronous method, so it has a synchronous signature. DoWorkAsync neither knows nor cares about the UI. The UIAction, which does care about the UI thread, pushes off the work onto a background thread using Task.Run.

As a general rule, try to “push” any Task.Run calls up out of your library methods as much as possible.

Leave a Comment