Search code examples
c#.netasynchronous.net-4.5c#-5.0

How does Task<int> become an int?


We have this method:

async Task<int> AccessTheWebAsync()
{ 
    HttpClient client = new HttpClient();

   Task<string> getStringTask = client.GetStringAsync("http://msdn.microsoft.com");

   // You can do work here that doesn't rely on the string from GetStringAsync.
   DoIndependentWork();

   string urlContents = await getStringTask;
   //The thing is that this returns an int to a method that has a return type of Task<int>
   return urlContents.Length;
}

Does an implicit conversion occur between Task<int> and int? If not, then what is happening? How is it implemented to work?


Solution

  • Does an implicit conversion occur between Task<> and int?

    Nope. This is just part of how async/await works.

    Any method declared as async has to have a return type of:

    • void (avoid if possible)
    • Task (no result beyond notification of completion/failure)
    • Task<T> (for a logical result of type T in an async manner)

    The compiler does all the appropriate wrapping. The point is that you're asynchronously returning urlContents.Length - you can't make the method just return int, as the actual method will return when it hits the first await expression which hasn't already completed. So instead, it returns a Task<int> which will complete when the async method itself completes.

    Note that await does the opposite - it unwraps a Task<T> to a T value, which is how this line works:

    string urlContents = await getStringTask;
    

    ... but of course it unwraps it asynchronously, whereas just using Result would block until the task had completed. (await can unwrap other types which implement the awaitable pattern, but Task<T> is the one you're likely to use most often.)

    This dual wrapping/unwrapping is what allows async to be so composable. For example, I could write another async method which calls yours and doubles the result:

    public async Task<int> AccessTheWebAndDoubleAsync()
    {
        var task = AccessTheWebAsync();
        int result = await task;
        return result * 2;
    }
    

    (Or simply return await AccessTheWebAsync() * 2; of course.)