valuetask.md
July 3, 2026 · View on GitHub
ValueTask
A dependency can be injected as ValueTask<T> and awaited when needed — an allocation-friendly alternative to Task<T> for values that are usually available synchronously. Bind the underlying type as usual and request ValueTask<T>; here DataProcessor awaits ValueTask<IConnection> before using the connection.
using Shouldly;
using Pure.DI;
DI.Setup(nameof(Composition))
.Bind<IConnection>().To<CloudConnection>()
.Bind<IDataProcessor>().To<DataProcessor>()
// Composition root
.Root<IDataProcessor>("DataProcessor");
var composition = new Composition();
var processor = composition.DataProcessor;
await processor.ProcessDataAsync();
interface IConnection
{
ValueTask<bool> PingAsync();
}
class CloudConnection : IConnection
{
public ValueTask<bool> PingAsync() => ValueTask.FromResult(true);
}
interface IDataProcessor
{
ValueTask ProcessDataAsync();
}
class DataProcessor(ValueTask<IConnection> connectionTask) : IDataProcessor
{
public async ValueTask ProcessDataAsync()
{
// The connection is resolved asynchronously, allowing potential
// non-blocking initialization or resource allocation.
var connection = await connectionTask;
await connection.PingAsync();
}
}
Running this code sample locally
- Make sure you have the .NET SDK 10.0 or later installed
dotnet --list-sdk
- Create a net10.0 (or later) console application
dotnet new console -n Sample
dotnet add package Pure.DI
dotnet add package Shouldly
- Copy the example code into the Program.cs file
You are ready to run the example 🚀
dotnet run
Note
ValueTask<T> reduces allocations compared to Task<T> when operations complete synchronously, making it ideal for high-performance scenarios.
The following partial class will be generated
partial class Composition
{
public IDataProcessor DataProcessor
{
[MethodImpl(MethodImplOptions.AggressiveInlining)]
get
{
ValueTask<IConnection> transientValueTaskIConnection;
// Creates the task result
IConnection localValue = new CloudConnection();
// Wraps it in ValueTask<T>
transientValueTaskIConnection = new ValueTask<IConnection>(localValue);
return new DataProcessor(transientValueTaskIConnection);
}
}
}
Class diagram:
---
config:
class:
hideEmptyMembersBox: true
---
classDiagram
CloudConnection --|> IConnection
DataProcessor --|> IDataProcessor
Composition ..> DataProcessor : IDataProcessor DataProcessor
DataProcessor *-- ValueTaskᐸIConnectionᐳ : ValueTaskᐸIConnectionᐳ
ValueTaskᐸIConnectionᐳ *-- CloudConnection : IConnection
namespace Pure.DI.UsageTests.BCL.ValueTaskScenario {
class CloudConnection {
<<class>>
+CloudConnection()
}
class Composition {
<<partial>>
+IDataProcessor DataProcessor
}
class DataProcessor {
<<class>>
+DataProcessor(ValueTaskᐸIConnectionᐳ connectionTask)
}
class IConnection {
<<interface>>
}
class IDataProcessor {
<<interface>>
}
}
namespace System.Threading.Tasks {
class ValueTaskᐸIConnectionᐳ {
<<struct>>
}
}
See also: