The following code does not compile
public ValueTask Foo()
{
return Task.Delay(1000);
}
but yields an Error CS0029: Cannot implicitly convert type 'System.Threading.Tasks.Task' to 'System.Threading.Tasks.ValueTask
as expected.
However, this
public async ValueTask Bar()
{
await Task.Delay(1000);
}
does compile fine.
I was just wondering how this works. Is this all down to compiler magic and its async-await syntactic sugar or is there something else going on?
For context: I came across this when implementing IAsyncDisposable.DisposeAsync()
.
Is this all down to compiler magic and its async-await syntactic sugar?
In short, yes. Whenever you await
, the compiler needs to generate a state machine for that method. The task returned from the method then, is one that "represents" the state machine, rather than the single task that you are awaiting.
As a result, it doesn't matter what tasks you are awaiting anymore. The compiler just has to build the state machine according to where your await
s are in your method, and then build a new task.
Compare the code generated from the following snippets on SharpLab:
1:
async Task Bar()
{
await Task.Delay(1000);
}
2:
async ValueTask Bar()
{
await Task.Delay(1000);
}
The only substantial difference is that one uses AsyncTaskMethodBuilder
to build the task being returned, and the other using AsyncValueTaskMethodBuilder
.
For more details about the difference of awaiting a task vs directly returning the task, see this chain of duplicates.
Title doesn't match what's being asked. In fact, the question proves it's possible.
If you want to return ValueTask
that represents a Task
whithout having a method turned into a state machine, you can:
public ValueTask Foo()
{
return new ValueTask(Task.Delay(1000));
}
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With