3

Say I have method such as this:

private async Task SomeMethod()
{
  await DoSomethingAsync();
  await DoSomethingElseAsync();
  return;
}

Given that DoSomethingElseAsync returns a Task it would seem like you should be able to do this:

private async Task SomeMethod()
{
  await DoSomethingAsync();
  return DoSomethingElseAsync();
}

but the compiler complains about this:

Since 'SomeMethod' 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>'?

Why is that?

Damien_The_Unbeliever
  • 234,701
  • 27
  • 340
  • 448
DJL
  • 2,060
  • 3
  • 20
  • 39
  • 4
    @YvetteColomb it's not an exact duplicate of *this* question. The OP isn't asking when to use await. This asks `why can't I return a Task?` – Panagiotis Kanavos Oct 10 '17 at 08:59
  • @YvetteColomb This is not duplicate, the question you are referring is when to use await and this one is asking why second method cannot simply return instead of writing await, I think english is very clear to identify both as different. – Akash Kava Oct 10 '17 at 08:59
  • 4
    Before the first `await DoSomethingAsync();` is completed - method has already returned to its caller (it's asynchronous method after all). So there is no way you can return specific value after that `await` - caller already received a return value at this point and moved forward. – Evk Oct 10 '17 at 09:07

3 Answers3

5

Its pretty much like how yield return and return works. for an iterator you have either of these methods

public IEnumerable<int> SomeIterator()
{
    for(int I = 0; I < 10; I++) yield return I;
}

public IEnumerable<int> SomeIterator()
{
    return Enumerable.Range(0, 10); // return result of another iterator.
}

but you cant have both. it doesn't work, because an iterator is either converted to a class by compiler to handle lazy iteration with yield, or its just like other normal methods that returns something else.

public IEnumerable<int> SomeIterator() // not valid
{
    for(int I = 0; I < 10; I++) yield return I;
    return Enumerable.Range(0, 10); 
}

The story is same about return and async/await. for method that has return type of Task you either return Task or use async/await.

for Task<T> if you use await you must return T but you can not return Task<T> because the method is compiled into state machine, then method must return T. (for Task method is void)

if you don't use async/await method will be exactly like other normal methods.

M.kazem Akhgary
  • 18,645
  • 8
  • 57
  • 118
  • This, in combination with Evk's comment makes a lot of sense. I still find it somewhat dissapointing though that `await Thing1(); await Thing2(); return` and `await Thing1(); return Thing2();` don't simply compile down to the same code under the hood, since it still makes logical sense (at least in my head!) – DJL Oct 10 '17 at 09:16
0

When you use await - control flow might leave current method and return back to the caller. Suppose DoSomethingAsync is some long running operation. You call SomeMethod. DoSomethingAsync task is started but then you cannot wait for it to complete inside that method - otherwise nothing will be "async". So control flow leaves Method and should provide a return value to the caller. Return value is a task which completes when whole SomeMethod is completed. It can complete with or without result (Task or Task<T> return value). For that reason what you return after await could not be return type of SomeMethod - it can only be result type T (if SomeMethod returns Task) or just simple return to indicate completion of SomeMethod if it returns simple Task.

Evk
  • 98,527
  • 8
  • 141
  • 191
0

In a normal method, return means "return this value, if any, from the method". In an async method, the meaning of return is changed to "set the result of the returned Task to this value, if any".

But you can't combine the two: in an async Task method, you can't directly return a Task. One reason for this is that if you awaited, the method actually already returned a Task and it can't return another one.

When it comes to returning, async Task method behaves like a void method, in that it only allows return;, but never return value;.

svick
  • 236,525
  • 50
  • 385
  • 514