According to the documentation a ValueTask<TResult>...
Provides a value type that wraps a
Task<TResult>and aTResult, only one of which is used.
My question is about the state machine that the C# compiler generates when the async keyword is encountered. Is it smart enough to generate a ValueTask<TResult> that wraps a TResult, when the result is available immediately, or one that wraps a Task<TResult>, when the result comes after an await? Here is an example:
static async ValueTask<DateTime> GetNowAsync(bool withDelay)
{
if (withDelay) await Task.Delay(1000);
return DateTime.Now;
}
static void Test()
{
var t1 = GetNowAsync(false);
var t2 = GetNowAsync(true);
}
Calling GetNowAsync(false) should return a TResult wrapper, because nothing is awaited, and calling GetNowAsync(true) should return a Task<TResult> wrapper, because a Task.Delay is awaited before the result becomes available. I am worried about the possibility that the state machine always returns Task wrappers, nullifying all the advantages of the ValueTask type over the Task (and keeping all the disadvantages). As far as I can tell the properties of the type ValueTask<TResult> offer no indication about what it wraps internally. I pasted the code above to sharplab.io, but the output didn't help me to answer this question either.