41

I created UWP app with Windows Template Studio that introduced at Build2017.

Below class is a part of generated code from it.

public class SampleModelService
{
    public async Task<IEnumerable<SampleModel>> GetDataAsync()
    {
        await Task.CompletedTask; // <-- what is this for?
        var data = new List<SampleModel>();

        data.Add(new SampleModel
        {
            Title = "Lorem ipsum dolor sit 1",
            Description = "Lorem ipsum dolor sit amet",
            Symbol = Symbol.Globe
        });

        data.Add(new SampleModel
        {
            Title = "Lorem ipsum dolor sit 2",
            Description = "Lorem ipsum dolor sit amet",
            Symbol = Symbol.MusicInfo
        });
        return data;
    }
}

My question is, what is the purpose and reason of await Task.CompletedTask; code in here? It actually does not have Task result receiver from it.

Youngjae
  • 24,352
  • 18
  • 113
  • 198
  • 1
    One could consider this a way to [suppress warning CS1998: This async method lacks 'await' operators and will run synchronously](https://stackoverflow.com/questions/13243975/) although in the linked thread there is the question on how a thrown _exception_ affects an async method. – Jeppe Stig Nielsen May 30 '23 at 14:08

3 Answers3

50

It is there to make it easier for later stage to implement async code calls without having to alter the signature thus preventing having to refactor the calling code.

Whilst the scaffolded sample code is synchronous, the Template Studio is designed specifically around an async data access layer, you are expected to implement your own data access by modifying the body of the generated methods.

If the async implementation were NOT implemented, there would be significant code changes throughout the templated app and it would be a very steep learning curve for new developers, the point of the template is to get up and running with minimal effort or even experience!

Another option would be to remove the async keyword from the method signature and that line and do

return Task.FromResult<IEnumerable<SampleModel>>(data); 

You see this construct when you need to return an awaitable Task due to an interface for example while the implementation has no async work to do.

In this case however, since it is a template they expect people to replace the await Task.Completed with something like await FetchDataFromDatabaseAsync();. Since the async keyword is already there it minimizes the needed changes to implement your own async call.

Anyway, without this await construct you can do this:

public class SampleModelService
{
    public Task<IEnumerable<SampleModel>> GetDataAsync()
    {
        var data = new List<SampleModel>();

        data.Add(new SampleModel
        {
            Title = "Lorem ipsum dolor sit 1",
            Description = "Lorem ipsum dolor sit amet",
            Symbol = Symbol.Globe
        });

        data.Add(new SampleModel
        {
            Title = "Lorem ipsum dolor sit 2",
            Description = "Lorem ipsum dolor sit amet",
            Symbol = Symbol.MusicInfo
        });

        return Task.FromResult<IEnumerable<SampleModel>>(data); 
     }
}

If there is no requirement to return a Task at all (you do not have any async code) then just remove it completely. (But then you have to refactor code that calls this method)

Reviewing this code I suspect someone is going to call an async method later in the development process and already anticipated that by specifying that this method returns a Task.

Chris Schaller
  • 13,704
  • 3
  • 43
  • 81
Peter Bons
  • 26,826
  • 4
  • 50
  • 74
  • 1
    So we can say, it is a kind of placeholder for `async` signature. is it right? – Youngjae May 21 '17 at 12:11
  • 5
    Well, whenever you `await` something you will need to add `async` to the method signature. For more in depth explanation as to why the `async` keyword is necessary please read this post: https://blogs.msdn.microsoft.com/ericlippert/2010/11/11/asynchrony-in-c-5-part-six-whither-async/. In this particular case it is a justification for adding the `async` keyword. Since this is a template they expect people to replace the `await Task.Completed` with something like `await FetchDataFromDatabaseAsync();` – Peter Bons May 21 '17 at 13:54
  • return Task.Run(()=>{xx })? – lindexi May 22 '17 at 00:53
  • Wouldn't the consumer have an expectation as to the exception handling semantics? What happens if the code throws an exception? Normally it should return a faulted task, but in this case it wouldn't; the exception would bubble up instead. – rory.ap Aug 23 '18 at 16:31
  • @rory.ap correct, to mitigate that you can catch exceptions and return `Task.FromException(exception);` – Peter Bons Jun 26 '19 at 14:17
  • Also, without this `await` compiler will emit `warning CS1998: This async method lacks 'await' operators and will run synchronously. Consider using the 'await' operator to await non-blocking API calls, or 'await Task.Run(...)' to do CPU-bound work on a background thread.` – OwnageIsMagic Oct 03 '20 at 15:07
  • I can't count the number of times I removed async keyword then put it back just to remove it again later. Same with Task.FromResult function call. This actually seems like a nice way to avoid all that hassle. Just design async first and stick await Task.CompletedTask when dealing with non-async code. – emt May 19 '22 at 20:35
2

await Task.CompletedTask makes it easier to implement this method as the first answer said, Since this implementation isn't time-consuming, and thus "await Task.CompletedTask;" or "return Task.FromResult(data);" both will run synchronously. You can use those two pattern mentioned above, but this method is designed to be an asynchronous method, so when your implementation is time-consuming but don't have any async code, use Task.Run to create a task.

0

The method is declared as async. Therefore the compiler expects it to await something, like a call to an external database.

Your code is synchronous, so the compiler will warn you, that there is a "code smell". You can suppress this warning by adding await Task.CompletedTask - which does nothing, but the compiler will be satisfied.

This would also be useful if you have a conditional await, e.g. when you check the method parameters or the external binding is not yet initialized.

Corbie
  • 819
  • 9
  • 31