OdeToCode IC Logo

Task.CompletedTask and Task.Result Tips

Thursday, January 18, 2018

In any method returning a Task, it is desirable to avoid using Task.Run if you can compute a result without going async. For example, if logic allows you to short-circuit a computation, or if you have a fake method in a test returning a pre-computed answer, then you don't need to use Task.Run.

Example:

Here is a method that is not going to do any work, but needs to return a task to fulfill an interface contract for a test:

public Task ComputationWithSideEffects(string someId)
{
    return Task.Run(() => {
        // i'm just here to simulate hard work
    });
}

Instead of returning the result of Task.Run, there are two helpers on the Task class that make the code more readable and require a bit less runtime overhead.

For the above scenario, I'd rather use Task.CompletedTask:

public Task ComputationWithSideEffects(string someId)
{
    return Task.CompletedTask;
}

What if the caller expects to receive a result from the task? In other words, what if you return a Task<T>? In this scenario, if you already have an answer, use Task.FromResult to wrap the answer.

public Task<Patience> FindPatience()
{
    if(cachedPatience != null) 
    {
        return Task.FromResult(cachedPatience);
    }
    else
    {
        return ImAlreadyGone();
    }
}