Before C# 7.0, the async methods supported the following return types.
From C# 7.0, an async method can return any type that has an accessible GetAwaiter
method. The object returned by the GetAwaiter
method must implement the ICriticalNotifyCompletion
interface.
Returning a Task
object from async methods can introduce performance bottlenecks in certain paths. Task
is a reference type, so using it means allocating an object.
Starting with C# 7.0, an asynchronous method also can return ValueTask
or ValueTask
ValueTask<TResult>
structure as a lightweight implementation of a generalized Task<TResult>
value.ValueTask<TResult>
type, you must add the System.Threading.Tasks.Extensions
NuGet package to your project.The following example uses the ValueTask<TResult>
structure to retrieve the value.
static readonly Random random = new Random();
public static async void PrintRandomNumberUsingValueTask()
{
int number = await GetNumber();
Console.WriteLine("Random number: {0}", number);
}
public static async ValueTask<int> GetNumber()
{
await Task.Delay(1);
return random.Next(1, 1000);
}
The ValueTask
and ValueTask<TResult>
are wrappers around Task
and Task<TResult>
with the distinction that they are defined using a struct
instead of a class
.
There is a major difference between Task
and ValueTask
.
Task
is a reference type and requires heap allocation.ValueTask
is a value type and is returned by value and required no heap allocation.ValueTask
when there is a high probability that a method won't have to wait for async
operations.