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.