Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Why does this async / await code generate "...not all code paths return a value"?

Hopefully this isn't a repeat, but there are 5000+ questions here with "not all code paths return a value"!

Quite simply, why does this method with a non-generic implementation compile just fine:

    public static async Task TimeoutAfter(this Task task, int millisecondsTimeout)
    {
        if (task == await Task.WhenAny(task, Task.Delay(millisecondsTimeout)))
            await task;
        else
            throw new TimeoutException();
    }

while this attempt to make the method generic generates a Return state missing / ...not all code paths return a value warning / error?:

    public static async Task<T> TimeoutAfter<T>(this Task<T> task, int millisecondsTimeout)
    {
        if (task == await Task.WhenAny(task, Task.Delay(millisecondsTimeout)))
            await task;
        else
            throw new TimeoutException();
    }
like image 924
HolySamosa Avatar asked Aug 24 '12 18:08

HolySamosa


2 Answers

In the second example you gave you didn't return anything. (See Chris Hannon's answer for why).

public static async Task<T> TimeoutAfter<T>(this Task<T> task, int millisecondsTimeout) {
    if (task == await Task.WhenAny(task, Task.Delay(millisecondsTimeout)))
        return await task; // return the Task of T
    else
        throw new TimeoutException();
}

In addition to what @ChrisHannon said, from the await documentation.

... if await is applied to the result of a method call that returns a Task<TResult>, then the type of the await expression is TResult. If await is applied to the result of a method call that returns a Task, then the type of the await expression is void. ...

like image 121
David Anderson Avatar answered Oct 20 '22 16:10

David Anderson


The non-generic Task type is somewhat equivalent to an awaitable void method. Just like a void method, you can't return anything from a method that has a return type of Task, which is why the first example compiles. The second example, though, expects a return value of the generic type and you aren't providing one in the path where you await another call.

Quoting from the MSDN reference on the async keyword, specifically about return types.

You use Task if no meaningful value is returned when the method is completed. That is, a call to the method returns a Task, but when the Task is completed, any await expression that's awaiting the Task evaluates to void.

like image 11
Chris Hannon Avatar answered Oct 20 '22 16:10

Chris Hannon