6

What is the best way to return a task that doesn't have a generic type parameter? In other words a task that represents an operation that doesn't return anything or returns void?

In other words, I am looking for alternatives for the following:

T value = default(T);
return Task.FromResult<T>(value); // and

var tcs = new TaskCompletionSource<T>();
tcs.SetResult(value);
return tcs.Task;

But for tasks that represent operations that are not supposed to return anything.

Water Cooler v2
  • 32,724
  • 54
  • 166
  • 336

2 Answers2

14

I'm not sure if this is strictly idiomatic, but I use Task.CompletedTask for this. A Task.FromResult is commonly used, but in all scenarios I can think of CompletedTask works identically, and makes more sense semantically.

Asad Saeeduddin
  • 46,193
  • 6
  • 90
  • 139
  • 3
    Yup - that's the best approach from .NET 4.6 onwards. – Jon Skeet Aug 07 '15 at 09:43
  • @Asad: Yes, I saw that this morning. It was added in 4.6 and is syntactic sugar for `FromResult`. – Water Cooler v2 Aug 07 '15 at 09:54
  • 1
    @WaterCoolerv2 Well it's just a new property, not really syntax sugar; and looking at the [reference source](http://referencesource.microsoft.com/#mscorlib/system/threading/Tasks/Task.cs,66f1c3e3e272f591) it doesn't seem to return a `Task.FromResult`. Still, the fact that it is 4.6 only makes `FromResult` the correct choice. – Asad Saeeduddin Aug 07 '15 at 10:00
  • My apologies. Reading this article (http://blogs.msdn.com/b/pfxteam/archive/2015/02/02/new-task-apis-in-net-4-6.aspx) led to me believe that it was syntactic sugar. You're right. It isn't. Thanks for pointing that out. Also, it does make a lot of sense in terms of its name representing what I want. Just that I can't use it still in the libraries that my VS 2015 Community RC is referencing. I wish we could vote for two answers at once. – Water Cooler v2 Aug 07 '15 at 10:04
11

Task<T> extends Task - so it's reasonably common to just use Task.FromResult<object> and provide an empty result. For example:

Task ret = Task.FromResult<object>(null);

(Or use a value type - it really doesn't matter much.)

Of course, as tasks are immutable you could create a singleton instance of this and return it every time you want to return a completed task. (I believe that's what the async/await infrastructure does, in fact - or at least did in beta releases...)

As Asad noted, you can use Task.CompletedTask, but only if you're targeting .NET 4.6. (Actually, it's not clear whether it's supporting in .NET 4.5 or not - the documentation shows ".NET Framework 4.6 and 4.5" as the version number, but then says "Supported in: 4.6"...)

Jon Skeet
  • 1,421,763
  • 867
  • 9,128
  • 9,194
  • Thank you. It took me some time to vote this as the correct answer because I was thinking of the implications. While the signature allows this, I was worried about what would happen if the consumer of that task was expecting the task to return something. But you're right. I am authoring the task and I know that it returns nothing. It doesn't matter what the consumer expects in ignorance. He may choose to await it or just throw it away (fire and forget). Either ways, it will work. – Water Cooler v2 Aug 07 '15 at 09:53
  • 2
    Previous to 4.6 you can call Task.WhenAll() with no arguments to expose Task.CompletedTask which is internal until 4.6 – Stephen Brickner Aug 07 '15 at 11:11
  • `Task.CompletedTask` doesn't seem to appear in portable as of Feb 2017. – Shimmy Weitzhandler Feb 18 '17 at 21:58