152

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?

bubbleking
  • 3,329
  • 3
  • 29
  • 49
Freeman
  • 5,691
  • 3
  • 29
  • 41
  • 1
    [Keep reading](http://msdn.microsoft.com/en-us/library/vstudio/hh524395.aspx). I assume the compiler takes care of that based on the `async` keyword. – D Stanley Oct 31 '12 at 13:33
  • 2
    @Freeman, Look at this great explanation: http://stackoverflow.com/a/4047607/280758 – qehgt Oct 31 '12 at 13:37

2 Answers2

227

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

kmad1729
  • 1,484
  • 1
  • 16
  • 20
Jon Skeet
  • 1,421,763
  • 867
  • 9,128
  • 9,194
  • 5
    can any details be offered for how it works under the hood, just curious. – Freeman Oct 31 '12 at 13:35
  • 13
    +1 Good answer as always. And why are you so pretty fast writing them?! – Felix K. Oct 31 '12 at 13:36
  • 14
    +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`). – dav_i Nov 18 '13 at 14:31
  • @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. – Jon Skeet Nov 18 '13 at 14:33
  • 2
    @JonSkeet But it doesn't make sense without the `await` - with `T foo = someTaskT;` you'd get "Cannot implicitly convert type `Task` to `T`" - in the same way I argue that it would make more sense to have a keyword for the inverse (wrapping in `Task`). 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!) – dav_i Nov 18 '13 at 14:55
  • 3
    @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. – Jon Skeet Nov 18 '13 at 14:58
  • @JonSkeet both of the links in your comment seem to be broken now. Can we have them updated if possible? Thanks. – akka16 Jan 31 '17 at 05:25
  • @akka16: The Tekpub screencast series is now on Pluralsight. For Eduasync, you want https://codeblog.jonskeet.uk/category/eduasync/ – Jon Skeet Jan 31 '17 at 06:44
  • It's good to know Author of C# in Depth is active here. – Don Dilanga Sep 09 '20 at 13:42
  • What's the point of using `await` instead of `.Result` in an asynchronous method B if the caller method A awaits the method B right away?, i.e. without doing any work between calling B and awaiting B. – Pedro Machado Oct 18 '22 at 11:12
  • @PedroMachado: If the task hasn't immediately completed, method B will "pause" (without consuming a thread) rather than blocking until the task has completed. – Jon Skeet Oct 18 '22 at 11:33
16

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.

Fábio Nascimento
  • 2,644
  • 1
  • 21
  • 27
Aniket Sharma
  • 1,000
  • 10
  • 16
  • 30
    that is not what i asked. – Freeman Oct 25 '16 at 09:14
  • 33
    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. – Eric Lippert Nov 19 '18 at 20:33
  • 1
    @EricLippert: Not clear your example. Can you please explain how Result can introduce deadlocks when await won't? – CharithJ Nov 03 '19 at 23:59
  • 4
    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. – Eric Lippert Nov 04 '19 at 00:02
  • 1
    @EricLippert. Will this have the same issue ? 'Task.Run(()=> AccessTheWebAndDouble()).Result;' – CharithJ Nov 06 '19 at 05:50
  • 1
    .Result can block and is generally considered a very bad idea. I can't believe this has any upvotes let alone 22. – db2 Jul 28 '21 at 14:27