Wiaoj.ObjectPool
0.0.1-alpha.69
dotnet add package Wiaoj.ObjectPool --version 0.0.1-alpha.69
NuGet\Install-Package Wiaoj.ObjectPool -Version 0.0.1-alpha.69
<PackageReference Include="Wiaoj.ObjectPool" Version="0.0.1-alpha.69" />
<PackageVersion Include="Wiaoj.ObjectPool" Version="0.0.1-alpha.69" />
<PackageReference Include="Wiaoj.ObjectPool" />
paket add Wiaoj.ObjectPool --version 0.0.1-alpha.69
#r "nuget: Wiaoj.ObjectPool, 0.0.1-alpha.69"
#:package Wiaoj.ObjectPool@0.0.1-alpha.69
#addin nuget:?package=Wiaoj.ObjectPool&version=0.0.1-alpha.69&prerelease
#tool nuget:?package=Wiaoj.ObjectPool&version=0.0.1-alpha.69&prerelease
Wiaoj.ObjectPool
A high-performance, thread-safe, and unified asynchronous/synchronous object pooling library for .NET.
Wiaoj.ObjectPool extends the capabilities of Microsoft.Extensions.ObjectPool by providing a unified API surface for both sync and async pools. It introduces true asynchronous support, blocking/bounded pools, factory pattern integration, and zero-allocation leasing. It is designed for high-throughput applications where garbage collection pressure must be minimized and resource management is critical.
🚀 Key Features
- ⚡ True Async Support: Native
IAsyncObjectPool<T>withValueTasksupport. Handles asynchronous creation (CreateAsync) and cleanup (TryResetAsync). - 🤝 Unified API: Provides a consistent, clean API surface for both
Microsoft's standard synchronous pools and our custom asynchronous pools. No need to switch contexts! - 🏭 Factory Integration: Seamlessly integrates with
IAsyncFactory<T>for complex object creation logic using Dependency Injection. - 🛡️ Hybrid Operation Modes:
- FIFO (Elastic): Lock-free, extremely fast. Creates new objects instantly if the pool is empty.
- Bounded (Blocking): Uses
SemaphoreSlim. Waits asynchronously if the pool limit is reached. Ideal for resource throttling (e.g., DB connections).
- 🧠 Smart Lifecycle Management: Supports
IResettable(Sync) andIAsyncResettable(Async) interfaces for self-managing objects. - 📦 True Zero-Allocation Leasing: Uses a value-type
struct(PooledObject<T>) to manage the lease lifecycle, ensuring 0 heap allocations duringGet/Returncycles.
📥 Installation
Install via NuGet Package Manager:
dotnet add package Wiaoj.ObjectPool
⚡ Quick Start (Synchronous)
For simple CPU-bound objects like StringBuilder or List<T>, use the standard synchronous pool. Our library wraps it cleanly.
1. Register in DI
using Wiaoj.ObjectPool.Extensions;
var builder = WebApplication.CreateBuilder(args);
// Simple registration (uses new T())
builder.Services.AddObjectPool<StringBuilder>();
// Or with custom factory and reset logic via Lambdas
builder.Services.AddObjectPool<List<int>>(
factory: () => new List<int>(),
resetter: list => { list.Clear(); return true; }
);
2. Inject and Use
public class StringService(IObjectPool<StringBuilder> pool)
{
public string BuildMessage()
{
// 'using' ensures the object is automatically returned to the pool
using PooledObject<StringBuilder> lease = pool.Lease();
StringBuilder sb = lease.Item;
sb.Append("Hello High Performance!");
return sb.ToString();
}
}
🔥 Advanced Usage (Asynchronous)
This is where Wiaoj.ObjectPool shines. Ideal for database connections, network streams, or any resource where creation/reset is costly and requires I/O.
1. Register Async Pool
builder.Services.AddAsyncPool<MyDbConnection>(
factory: async ct => await MyDbConnection.CreateAsync(ct),
resetter: async conn => await conn.ResetStateAsync(),
options =>
{
// Wait asynchronously if 50 connections are already in use.
options.MaximumRetained = 50;
options.AccessMode = PoolAccessMode.Bounded;
}
);
2. Inject and Use
public class DataService(IAsyncObjectPool<MyDbConnection> dbPool)
{
public async Task ProcessDataAsync()
{
// Leases a connection asynchronously.
// If pool is 'Bounded' and full, this line awaits until a slot opens.
// Supports 'await using' for async disposal.
await using var lease = await dbPool.LeaseAsync();
var connection = lease.Item;
await connection.ExecuteQueryAsync("SELECT * FROM Users");
}
}
🧠 Defining Pool Logic: Strategies
Wiaoj.ObjectPool offers flexibility in how you define object creation and cleanup.
1. The "OOP" Way (IResettable) - Recommended
Best for objects that know how to clean themselves. No external logic required in Program.cs.
Step 1: Implement IResettable (Sync) or IAsyncResettable (Async).
public class SocketClient : IAsyncResettable
{
public async ValueTask<bool> TryResetAsync()
{
await SendResetCommandAsync(); // Async cleanup!
return true;
}
}
Step 2: Register
// No factory or resetter needed!
builder.Services.AddAsyncResettablePool<SocketClient>();
2. The "Factory" Way (IAsyncFactory)
Best when object creation is complex and already handled by an IAsyncFactory<T> implementation in your DI container.
// 1. You already have a factory registered
builder.Services.AddSingleton<IAsyncFactory<MyService>, MyServiceFactory>();
// 2. Register the pool (It automatically resolves the factory!)
builder.Services.AddAsyncFactoryPool<MyService>(
resetter: async svc => { /* Custom reset logic */ return true; }
);
⚙️ Configuration Modes
You can control the pool's behavior via ObjectPoolOptions.AccessMode:
| Mode | Description | Best For |
|---|---|---|
| FIFO (Default) | Lock-Free / Elastic. If the pool is empty, it immediately creates a new object. Limits only apply when returning to the pool. | CPU-bound objects (StringBuilder, buffers) where latency matters most. |
| Bounded | Throttled / Blocking. If the pool reaches the MaximumRetained limit, LeaseAsync() will await until an object is returned. |
Limited resources (DB Connections, Throttled API Clients) to prevent system overload. |
⚠️ Best Practices: Zero-Allocation Leasing
To achieve 0 heap allocations during the Lease operation, PooledObject<T> is designed as a struct (Value Type).
Important Rule: Do NOT copy the leased struct or pass it by value to other methods. Doing so could result in double-disposal. Always use it tightly within a using or await using block.
Correct:
await using var lease = await pool.LeaseAsync();
var client = lease.Item;
Incorrect:
var lease1 = pool.Lease();
var lease2 = lease1; // ❌ DO NOT DO THIS! (Copies the struct)
📄 License
This project is licensed under the MIT License.
| Product | Versions Compatible and additional computed target framework versions. |
|---|---|
| .NET | net10.0 is compatible. net10.0-android was computed. net10.0-browser was computed. net10.0-ios was computed. net10.0-maccatalyst was computed. net10.0-macos was computed. net10.0-tvos was computed. net10.0-windows was computed. |
-
net10.0
- Microsoft.Extensions.DependencyInjection.Abstractions (>= 10.0.0)
- Microsoft.Extensions.ObjectPool (>= 10.0.0)
- Wiaoj.Concurrency (>= 0.0.1-alpha.69)
- Wiaoj.Primitives (>= 0.0.1-alpha.69)
NuGet packages (3)
Showing the top 3 NuGet packages that depend on Wiaoj.ObjectPool:
| Package | Downloads |
|---|---|
|
Tyto
Package Description |
|
|
Tyto.Context
Package Description |
|
|
Wiaoj.BloomFilter
Package Description |
GitHub repositories
This package is not used by any popular GitHub repositories.
| Version | Downloads | Last Updated |
|---|---|---|
| 0.0.1-alpha.69 | 54 | 5/15/2026 |
| 0.0.1-alpha.68 | 46 | 5/15/2026 |
| 0.0.1-alpha.67 | 43 | 5/14/2026 |
| 0.0.1-alpha.66 | 42 | 5/13/2026 |
| 0.0.1-alpha.65 | 46 | 5/12/2026 |
| 0.0.1-alpha.64 | 49 | 5/12/2026 |
| 0.0.1-alpha.63 | 44 | 5/12/2026 |
| 0.0.1-alpha.62 | 56 | 5/8/2026 |
| 0.0.1-alpha.61 | 45 | 5/6/2026 |
| 0.0.1-alpha.60 | 46 | 5/5/2026 |
| 0.0.1-alpha.59 | 42 | 5/5/2026 |
| 0.0.1-alpha.58 | 42 | 5/5/2026 |
| 0.0.1-alpha.57 | 40 | 5/5/2026 |
| 0.0.1-alpha.56 | 41 | 5/5/2026 |
| 0.0.1-alpha.55 | 42 | 5/5/2026 |
| 0.0.1-alpha.54 | 64 | 4/25/2026 |
| 0.0.1-alpha.53 | 54 | 4/18/2026 |
| 0.0.1-alpha.52 | 1,225 | 4/16/2026 |
| 0.0.1-alpha.51 | 53 | 4/16/2026 |
| 0.0.1-alpha.50 | 128 | 4/15/2026 |