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?
async
keyword.
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
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.)
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.
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.
Success story sharing
async
/await
and I find this extremely non-intuitive. IMO, there should be a keyword or similar at thereturn
to make this clear, e.g.return async result;
(in the same way thatawait result
"unwraps" theT
from theTast<T>
).await
- withT foo = someTaskT;
you'd get "Cannot implicitly convert typeTask<T>
toT
" - in the same way I argue that it would make more sense to have a keyword for the inverse (wrapping inTask<T>
). I'm all for removing fluff but in this case I think it provides an unnecessary obfuscation withinasync
methods. (Obviously the point is moot because the powers that be have already spoken/coded!)async
, I think that's enough.