Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Return a Task instead of awaiting the inner method call [duplicate]

I see some colleague code where he chooses to not await the database call and just return the Task. E.g.

public Task<UpdateResult> AddActivityAsync(ClaimsPrincipal principal, Activity activity)
{
    return _userManager.SaveToDatabaseAsync(principal, activity);
}

as _userManager.SaveToDatabaseAsync is async, I would have implemented this way

public async Task<UpdateResult> AddActivityAsync(ClaimsPrincipal principal, 
                                                                      Activity activity)
{
    return await _userManager.SaveToDatabaseAsync(principal, activity);
}

The calling method of this method always await it:

await _profile.AddActivityAsync(..., ...)

Is there any benefit to not make the inner method async and just return the Task, letting the caller await it ? I thought we had to write Async all the way down...

like image 241
Raphaël Avatar asked Mar 10 '17 10:03

Raphaël


2 Answers

It depends on the situation.

You must await, for example, if the code to be awaited is bound to an object that is in an using context (or gets manually disposed):

using (SomeDisposableType obj = ...)
{
    await obj.SomeOperationAsync();
}

If you returned the task without awaiting it, then the method might complain that the object had been disposed before it could have finished its job. (not all disposable objects throw an ObjectDisposedException if you attempt to perform something on them after they get disposed but it is generally a good idea to assume so). Consider the opposite:

using (SomeDisposableType obj = ...)
{
    // This returns the Task that represents the async operation,
    // and because it returns, the control goes out of the using
    // scope, and therefore obj gets disposed.
    return obj.SomeOperationAsync();
}

So there are cases when awaiting is necessary. If that is not the case, I can't really think of a reason why you couldn't return the Task itself.

like image 164
Balázs Avatar answered Oct 05 '22 22:10

Balázs


You do not need to await a method which returns a Task<T>, the code will just run asynchronously if you have the async keyword on the method. You colleague has removed that and so is running synchronously deliberately and lets the calling code implement it if they so choose.

It depends at which layer this code is being run. If it is deep it may be better to let the higher code layers choose ansynchronous execution and maintain control there.

You definitely don't need to 'write async all the way down'. The purpose of the async keyword is simply to mark a method as being able to return a Task<T> and be able to use the await keyword. The await keyword is what invokes the framework to execute the Task and provide asynchronous processing.

TL;DR: It's a choice.

I welcome anyone improving or correcting me on this as I am no guru.

like image 42
Matt W Avatar answered Oct 06 '22 00:10

Matt W