Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Return Task instead of Task<TResult> from TaskCompletionSource

As I have seen in several coding examples, as well as, what I can understand from this SO question I should be able to return a non-generic Task from TaskCompletionSource

(i.e., Return Task and not Task<TResult> from the method UploadFilesAsync) 

Yet the following code:

public async Task UploadFilesAsync(string fileAPath, string fileBPath)
{
   var tcs = new TaskCompletionSource<Object>();

   //logic to process files

   try
   {
      await Task.WhenAll(uploadFileAAsync(fileAPath), 
                         uploadFileBAsync(fileBPath));
      tcs.TrySetResult(null);
   }
   catch (Exception e)
   {
      tcs.SetException(e);
   }
   finally
   {
      //logic to clean up files
   }
   return tcs.Task;
}

Produces the following syntax error

'UploadFilesAsync(string, string)' is an async method that returns 'Task', 
a return keyword must not be followed by an object expression. 
Did you intend to return 'Task<T>'?

I am targeting .NET 4.5. I know it can work to return Task(of object) but that makes the API feel "dirty". Is it preferred practice to return Task(of object) or is it possible to return Task (non-generic as shown in the code)?

like image 830
Jonathan Harrison Avatar asked Apr 26 '13 06:04

Jonathan Harrison


People also ask

How do I return a task in async?

If you use a Task return type for an async method, a calling method can use an await operator to suspend the caller's completion until the called async method has finished. In the following example, the WaitAndApologizeAsync method doesn't contain a return statement, so the method returns a Task object.

What is a task completion source?

In many scenarios, it is useful to enable a Task<TResult> to represent an external asynchronous operation. TaskCompletionSource<TResult> is provided for this purpose. It enables the creation of a task that can be handed out to consumers.

Can Task return a value?

The client can access the task's result by using the same Result property of the same task after the task completes. Returning a value after the task executes is necessary if you need to process the result. You can return different types of results from a task including user defined objects.

Is Task run asynchronous?

NET, Task. Run is used to asynchronously execute CPU-bound code.


1 Answers

I know it can work to return Task(of object)

Well, that won't do what you expect it to.

The trouble is that you're trying to return a task... and an async method automatically wraps the return value in another task. It's not clear why you're using an async method at all here, to be honest. Why not just write this:

public Task UploadFilesAsync(string fileAPath, string fileBPath)
{
    return Task.WhenAll(uploadFileAAsync(fileAPath), uploadFileBAsync(fileBPath));
}

Does that not do what you want? You just want a task which completes when both of the "suboperations" have completed, right? That's exactly what Task.WhenAll returns. Your method is still non-blocking - it won't wait until the operations have completed before it returns. It's just that you're using the fact that Task.WhenAll is non-blocking to achieve that, instead of an async method.

EDIT: Note that if you wanted to do something else in that method as well, you could make it an async method without using TaskCompletionSource yourself:

public async Task UploadFilesAsync(string fileAPath, string fileBPath)
{
    // Upload the files
    await Task.WhenAll(uploadFileAAsync(fileAPath), uploadFileBAsync(fileBPath));
    await SomethingElseAsync();
    MaybeDoSomethingCheap();
}

Note that even though the async method here returns Task, you don't have a return value - the async/await machinery handles all of that for you, returning a task which will complete when MaybeDoSomethingCheap() has finished, or fault if an exception is thrown.

like image 136
Jon Skeet Avatar answered Sep 17 '22 12:09

Jon Skeet