If I have a method like
Task<bool> LongProcessTaskAsync();
Would it be a better practice to return a started task
return Task<bool>.Factory.StartNew(() => { ... });
or just return new Task<bool>(() => ...)
Personally, I prefer the first method but I'd rather be consistent will other API's and libraries.
Is returning a not-started task ever more appropriate?
An exception that's raised in a method that returns a Task or Task<TResult> is stored in the returned task. If you don't await the task or explicitly check for exceptions, the exception is lost. If you await the task, its exception is rethrown. As a best practice, you should always await the call.
Task, for an async method that performs an operation but returns no value. Task<TResult>, for an async method that returns a value.
The recommended return type of an asynchronous method in C# is Task. You should return Task<T> if you would like to write an asynchronous method that returns a value. If you would like to write an event handler, you can return void instead. Until C# 7.0 an asynchronous method could return Task, Task<T>, or void.
Whatever you return from async methods are wrapped in a Task . If you return no value(void) it will be wrapped in Task , If you return int it will be wrapped in Task<int> and so on.
In the case of async/await methods, the Task will already be started. AFAIK, all the BCL methods added for Task-based versions return already-started Tasks. It would be kinda weird not to, since the common consumer case is now:
var foo = await GetFooAsync();
[EDIT] Based on Stephen pointing out that the TAP guidelines covers this (and he already includes a link to the guidelines), I'll include a quote of the relevant bit from page 4 (in The Task-based Asynchronous Pattern Defined -> Behavior -> Task Status), and I've added bold+italics around the key parts.
Task Status
The Task class provides a life cycle for asynchronous operations, and that cycle is represented by the TaskStatus enumeration. In order to support corner cases of types deriving from Task and Task as well as the separation of construction from scheduling, the Task class exposes a Start method. Tasks created by its public constructors are referred to as “cold” tasks, in that they begin their life cycle in the non-scheduled TaskStatus.Created state, and it’s not until Start is called on these instances that they progress to being scheduled. All other tasks begin their life cycle in a “hot” state, meaning that the asynchronous operations they represent have already been initiated and their TaskStatus is an enumeration value other than Created.
All tasks returned from TAP methods must be “hot.” If a TAP method internally uses a Task’s constructor to instantiate the task to be returned, the TAP method must call Start on the Task object prior to returning it. Consumers of a TAP method may safely assume that the returned task is “hot,” and should not attempt to call Start on any Task returned from a TAP method. Calling Start on a “hot” task will result in an InvalidOperationException (this check is handled automatically by the Task class).
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With