How does Task<int> become an int?
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 typeT
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.
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, 2022Comments
-
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>
andint
? If not, then what is happening? How is it implemented to work?-
D Stanley over 11 yearsKeep reading. I assume the compiler takes care of that based on the
async
keyword. -
qehgt over 11 years@Freeman, Look at this great explanation: stackoverflow.com/a/4047607/280758
-
-
Freeman over 11 yearscan any details be offered for how it works under the hood, just curious.
-
Felix K. over 11 years+1 Good answer as always. And why are you so pretty fast writing them?!
-
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 thereturn
to make this clear, e.g.return async result;
(in the same way thatawait result
"unwraps" theT
from theTast<T>
). -
Jon Skeet over 10 years@dav_i: The difference is that without the
await
, the expression would still make sense - whereasreturn
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 over 10 years@JonSkeet But it doesn't make sense without the
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!) -
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 over 7 yearsthat is not what i asked.
-
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 over 7 years@akka16: The Tekpub screencast series is now on Pluralsight. For Eduasync, you want codeblog.jonskeet.uk/category/eduasync
-
Eric Lippert over 5 yearsThis 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 over 4 years@EricLippert: Not clear your example. Can you please explain how Result can introduce deadlocks when await won't?
-
Eric Lippert over 4 yearsAwait 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 over 4 years@EricLippert. Will this have the same issue ? 'Task.Run(()=> AccessTheWebAndDouble()).Result;'
-
Don Dilanga over 3 yearsIt's good to know Author of C# in Depth is active here.
-
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.