How does Task<int> become an int?

133,092

Solution 1

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.)

Solution 2

No requires converting the Task to int. Simply Use The Task Result.

int taskResult = AccessTheWebAndDouble().Result;

public async Task<int> AccessTheWebAndDouble()
{
    int task = AccessTheWeb();
    return task;
}

It will return the value if available otherwise it return 0.

Share:
133,092
Freeman
Author by

Freeman

C# \ .NET Developer, Silverlight, WPF, Windows Phone, ASP.NET MVC, SQL Server, Windows Server, and other .NET stuff while trying to keep in mind clean and optimized code. Also a bit of a C++ amateur as well.

Updated on July 08, 2022

Comments

  • Freeman
    Freeman almost 2 years

    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?

  • Freeman
    Freeman over 11 years
    can any details be offered for how it works under the hood, just curious.
  • Felix K.
    Felix K. over 11 years
    +1 Good answer as always. And why are you so pretty fast writing them?!
  • dav_i
    dav_i over 10 years
    +1: Just started looking into async/await and I find this extremely non-intuitive. IMO, there should be a keyword or similar at the return to make this clear, e.g. return async result; (in the same way that await result "unwraps" the T from the Tast<T>).
  • Jon Skeet
    Jon Skeet over 10 years
    @dav_i: The difference is that without the await, the expression would still make sense - whereas return is unambiguous. It may be a bit more of a pain the first time you use it, but I think once you're used to it you'll be glad there isn't the extra fluff.
  • dav_i
    dav_i over 10 years
    @JonSkeet But it doesn't make sense without the await - with T foo = someTaskT; you'd get "Cannot implicitly convert type Task<T> to T" - in the same way I argue that it would make more sense to have a keyword for the inverse (wrapping in Task<T>). I'm all for removing fluff but in this case I think it provides an unnecessary obfuscation within async methods. (Obviously the point is moot because the powers that be have already spoken/coded!)
  • Jon Skeet
    Jon Skeet over 10 years
    @dav_i: The assignment doesn't make sense, but the rest does. And there are cases where the whole statement would make sense - although it might not be useful. Given that the method is already declared async, I think that's enough.
  • Freeman
    Freeman over 7 years
    that is not what i asked.
  • akka16
    akka16 over 7 years
    @JonSkeet both of the links in your comment seem to be broken now. Can we have them updated if possible? Thanks.
  • Jon Skeet
    Jon Skeet over 7 years
    @akka16: The Tekpub screencast series is now on Pluralsight. For Eduasync, you want codeblog.jonskeet.uk/category/eduasync
  • Eric Lippert
    Eric Lippert over 5 years
    This does not answer the question. But more importantly, this is very bad advice. You should almost never use Result; it can cause deadlocks! Consider for example this workflow: (1) Write a note that says "mow the lawn". (2) Wait for the lawn to be mowed (3) Eat a sandwich, (4) Do whatever it says on the note". With that workflow, you never eat a sandwich or mow the lawn, because step 2 is a synchronous wait on something that you will do in the future. But that's the workflow that you are describing here.
  • CharithJ
    CharithJ over 4 years
    @EricLippert: Not clear your example. Can you please explain how Result can introduce deadlocks when await won't?
  • Eric Lippert
    Eric Lippert over 4 years
    Await means to do something while you're waiting for the result and that something can include doing work to compute the result. But synchronous waits do nothing while you wait which means you could be preventing the work from being done.
  • CharithJ
    CharithJ over 4 years
    @EricLippert. Will this have the same issue ? 'Task.Run(()=> AccessTheWebAndDouble()).Result;'
  • Don Dilanga
    Don Dilanga over 3 years
    It's good to know Author of C# in Depth is active here.
  • db2
    db2 almost 3 years
    .Result can block and is generally considered a very bad idea. I can't believe this has any upvotes let alone 22.