Reputation: 18551
If you specify that a method is an async method by using an Async or async modifier, you enable the following two capabilities... The marked async method can itself be awaited by methods that call it.
But another page gives this example:
private async Task SumPageSizesAsync()
{
// To use the HttpClient type in desktop apps, you must include a using directive and add a
// reference for the System.Net.Http namespace.
HttpClient client = new HttpClient();
// . . .
Task<byte[]> getContentsTask = client.GetByteArrayAsync(url);
byte[] urlContents = await getContentsTask;
// Equivalently, now that you see how it works, you can write the same thing in a single line.
//byte[] urlContents = await client.GetByteArrayAsync(url);
// . . .
}
Here we see it call a function GetByteArrayAsync
which is not equipped with the async keyword, and yet the caller is able to await on the result.
Task<T>
, and the same function marked as async?Upvotes: 2
Views: 311
Reputation: 10607
From async/await faq (emphasis mine):
What does the “async” keyword do when applied to a method?
When you mark a method with the “async” keyword, you’re really telling the compiler two things:
- You’re telling the compiler that you want to be able to use the “await” keyword inside the method (you can use the await keyword if and only if the method or lambda it’s in is marked as async). In doing so, you’re telling the compiler to compile the method using a state machine, such that the method will be able to suspend and then resume asynchronously at await points.
- You’re telling the compiler to “lift” the result of the method or any exceptions that may occur into the return type. For a method that returns Task or Task, this means that any returned value or exception that goes unhandled within the method is stored into the result task. For a method that returns void, this means that any exceptions are propagated to the caller’s context via whatever “SynchronizationContext” was current at the time of the method’s initial invocation.
So, think of it as a syntactic sugar over plain old asynchronous .NET model: more compiler checks, less code, and completely indifferent from the caller perspective (caller either awaits the result inside async
method or uses other TPL primitives, or even blocks).
Actually, if you check the source code of the GetByteArrayAsync method, it is simply a wrapper over GetContentAsync method constructing the resulting Task
with TaskCompletionSource
and continuation-passing style.
private Task<T> GetContentAsync<T>(Uri requestUri, HttpCompletionOption completionOption, T defaultValue,
Func<HttpContent, Task<T>> readAs)
{
TaskCompletionSource<T> tcs = new TaskCompletionSource<T>();
GetAsync(requestUri, completionOption).ContinueWithStandard(requestTask =>
{
if (HandleRequestFaultsAndCancelation(requestTask, tcs))
{
return;
}
HttpResponseMessage response = requestTask.Result;
if (response.Content == null)
{
tcs.TrySetResult(defaultValue);
return;
}
try
{
readAs(response.Content).ContinueWithStandard(contentTask =>
{
if (!HttpUtilities.HandleFaultsAndCancelation(contentTask, tcs))
{
tcs.TrySetResult(contentTask.Result);
}
});
}
catch (Exception ex)
{
tcs.TrySetException(ex);
}
});
return tcs.Task;
}
Upvotes: 2
Reputation: 27673
As far as I can tell it's not being awaited. The Task
is.
The marked async method can itself be awaited
- that's for methods. A Task
doesn't need that in order to be awaitable (which is what you're doing in await getContentsTask
).
This also answers part 2 - The difference is that the one that returns Task
and is not marked async
cannot be awaited. Which is what MSDN says in the quoted text.
(I might be wrong, of course.)
Upvotes: -1
Reputation: 116548
Is MSDN wrong when it says that the async modifier enables callers to await?
No. It does allow callers to await as it rewrites your method to return a Task
/Task<T>
. But it isn't the only way to do so. Any method that returns an awaitable (e.g. Task<bool>
, YieldAwaitable
) enables the callers to await.
From the caller's perspective, what's the difference between a function that returns
Task<T>
, and the same function marked asasync
?
If it's implemented correctly, there shouldn't be any difference. The async
and await
keywords are a way for the compiler to help you write asynchronous code. But they are not necessary. You can (and you always could have) write asynchronous code without them.
Take Task.Delay
for example. It creates a task, sets a timer, configures the timer to complete the task after some time and returns the task. It doesn't use async-await and it doesn't need to. But by returning a task it allows the caller to await it.
In fact, a lot of the task-returning methods in the .NET framework don't use async-await internally as they are the "root" asynchronous methods. They return a task but don't have a task to await themselves.
Upvotes: 4
Reputation: 59020
An async
modifier allows you to use the await
keyword within that method. Any Task
can be awaited within a method marked async
-- the Task
represents an ongoing activity that may or may not already be complete when it is returned to the caller.
Upvotes: 1
Reputation: 127563
Do do not await a function, you await a Task
or a Task<T>
that a function returns1. In any examples where you see await client.GetByteArrayAsync(url)
there is a hidden implicit Task<byte[]>
that gets "passed" between the client.GetByteArrayAsync(url)
and the await
.
You question is similar to asking "How does the +
work when you do
int result = 1 + 2;
vs when you do
int two = 2;
int result = 1 + two;
The documentation states it is for adding two numbers together, but I am not adding two numbers in the 2nd example I am adding a number and a variable."
1: It is a little more completed than that, but for 99% of the time just think of it that way.
Upvotes: 3