Working with ValueTask in C#

C# Programming Guide

Asynchronous programming has been in use for a long time. From the time the Task Parallel Library (TPL) was introduced, developers have been using the Task class to write asynchronous code. The ValueTask struct is a new type introduced in C# 7.0 that provides a way to work with time-sensitive tasks with less resource consumption (memory, CPU, etc.) overhead.

This C# programming tutorial explains what a ValueTask struct is and how it can improve a developer’s productivity.

Want to learn .NET development in a course or class environment? Check out our list of the Top Online Courses to Learn .NET.

What is ValueTask in C#

ValueTask provides certain benefits over Task; while Task is a reference type with one field, a ValueTaskis a value type with two fields. Asynchronous methods that return ValueTaskwill also have larger state machines because they need to accommodate one struct containing two fields instead of just one reference to the Task.

Despite the advantages of ValueTask, there are some drawbacks to utilizing it instead of Task. Note that a ValueTask has two fields, while Task is a reference type with a single field. As a result, utilizing a ValueTask involves dealing with additional data, since a method call would return two data fields instead of one.

To avoid allocations and to have a more efficient task system, developers should use Task, rather than ValueTask. This is because ValueTask requires AsTask, which incurs allocation. Use Task when possible and ValueTask when not available.

Furthermore, if you await a method that returns a ValueTask, the state machine for that asynchronous function will be more complex, since it must manage a struct with two fields rather than just a single reference as in the case of a Task.

If your code is always asynchronous, (i.e., if the action will not finish immediately), use Task. When an asynchronous action’s result is already available or a cached result is already available, use ValueTask.

The Anatomy of Task and ValueTask in C#

Task and ValueTask are the two most common awaitable types in C#. A Task describes the status of an operation, such as whether it has been finished, cancelled, and so on. Asynchronous methods may either return a Task or a ValueTask. Since Task is a reference type, returning it from an asynchronous method requires allocating it every time the method is invoked.

The disadvantage of using Task is that memory will be allocated in the managed heap each time you return a Task object. If the outcome of the action performed by your method is instantly accessible, or completes synchronously, this allocation is unnecessary and hence expensive. This is precisely when ValueTask comes in handy.

ValueTask has two key advantages. First, since it does not need heap allocation, usage of ValueTask increases efficiency. Second, it is simple to implement and use. When the result of an asynchronous function is instantly available, you may avoid the additional cost of allocation by returning ValueTask rather than Task, since “T” here denotes a structure and a struct in C# is a value type (in contrast to the “T” in Task, which denotes a class).

Unlike a class, a struct is a value type that is allocated not in the heap, but the stack memory. Since stack allocation is much cheaper compared to heap, this explains why ValueTask consumes much fewer resources than Task and is high-performant.

A ValueTask cannot be blocked; if you need to block on a ValueTask, use the AsTask function to convert the ValueTask into a Task, and then block on the resultant Task object. Additionally, each ValueTask can only be used once. In this context, the term consume indicates that a ValueTask may asynchronously wait for (await) the process to finish or use AsTask to convert it to a Task. On the contrary, ValueTasks should only be used just once before they are disposed of.

Read: Top Productivity Tools for .NET Developers

Benefits of ValueTask in C#

Incidentally, ValueTask was first introduced in .NET Core 2.0 as a struct that was capable of wrapping either a T or a Task instance. The main benefit of using the ValueTask Struct is that it allows you to manage time-sensitive tasks more effectively.

This is because the struct can be used to encapsulate the state and provide a way to track progress and status. Additionally, the struct can be used to create asynchronous tasks, making your code more efficient.

How to Program ValueTask in C#

Refer to the C# code given below, which shows that the MemoryStream.ReadAsync method returns a ValueTask instance:

public override ValueTask ReadAsync(byte[] buffer, int offset, int count)
{
    try
    {
        int bytesRead = Read(buffer, offset, count);
        return new ValueTask(bytesRead);
    }
    catch (Exception e)
    {
        return new ValueTask(Task.FromException(e));
    }
}

Synchronous Implementation of ValueTask in C#

Now consider the following interface named IAuthorRepository:

public interface IAuthorRepository
{
    ValueTask GetAuthors();
}

Refer to the following code listing that shows how you can return ValueTask instances from a method in C#:

public class AuthorRepository : IAuthorRepository
 {
       public ValueTask GetAuthors()
        {
            var value = default(T);
            return new ValueTask(value);
        }
 }

Note that, to work with ValueTask, developers must include the System.Threading.Tasks namespace in your program.

Asynchronous Implementation of ValueTask in C#

Here is an asynchronous implementation of ValueTask. Refer to the code listing given below that shows an asynchronous implementation of ValueTask in C#:

public interface IAuthorRepository
{
    ValueTask GetAuthorsAsync();
}
public class AuthorRepository : IAuthorRepository
 {
    public ValueTask GetAuthorsAsync()
    {
       var value = default(T);
       await Task.Delay(100);
       return value;
    }
 }

Final Thoughts on ValueTask in C#

ValueTask is a value type that can be returned asynchronously from a method marked with the async keyword. A ValueTask struct is a type defined in the System.Threading.Tasks namespace. ValueTask is designed to represent tasks that do not require a lot of CPU time or memory.

ValueTask structs are lightweight, have no overhead, and they work with any type of threading model (asynchronicity) perfectly. You can take advantage of ValueTask to write high performance asynchronous code in C#.

Read more C# programming and software development tutorials.

Joydip Kanjilal
Joydip Kanjilal
A Microsoft Most Valuable Professional in ASP.NET, Speaker, and Author of several books and articles. More than 25 years of experience in IT with more than 18 years in Microsoft .NET and its related technologies. He was selected as a Community Credit Winner at http://www.community-credit.com several times. He has authored 8 books and more than 500 articles in some of the most reputed sites worldwide including MSDN, Info World, CodeMag, Tech Beacon, Tech Target, Developer, CodeGuru, and more.

More by Author

Must Read