The Task
class is a vital element to async/await operations. Async functions must return Task-wrapped objects, as such:
public async Task<int> LongCalculation() { int value = await SomeLongAsyncTask(); return value; }
Work with async/await long enough and you'll come across Task.CompletedTask
. According to the official documentation. This static property that simply "returns a task whose Status property is set to RanToCompletion.".
And? Why would I use it?
Glad you asked. I've found two uses:
To avoid warnings in non-async async functions
Sometimes you define a function that may later be async, but the first implementation isn't (hence the "non-async async"). When you go to compile, the compiler complains that your async function doesn't have an await in it.
Here's a simple way around that:
public async Task<int> LongCalculation() { await Task.CompletedTask; int value = 123; return value; }
During implementations of interfaces implemented as sync
You may want to define an interface that later can be used either Sync or Async. Such as:
public interface IDoSomeWork { Task Work(); }
Given this, you can create two different implementations, one sync, the other async. Here's the sync version:
Implementation #1: Syncpublic class TestOneSync : IDoSomeWork { public Task Work() { // Do some sync work return Task.CompletedTask; } }
Notice this version does NOT include the async
in the function definition. All that's needed is to return a Task object. In this case Task.CompletedTask works great.
public interface TestTwoAsync : IDoSomeWork { public async Task Work() { // Do some async work return; } }
In this case the Work
function truly is async, all only needs a simple return.
Most likely there are other uses for Task.CompletedTask
, but here are two simple examples.