Wiaoj.ObjectPool
0.0.1-alpha.32
dotnet add package Wiaoj.ObjectPool --version 0.0.1-alpha.32
NuGet\Install-Package Wiaoj.ObjectPool -Version 0.0.1-alpha.32
<PackageReference Include="Wiaoj.ObjectPool" Version="0.0.1-alpha.32" />
<PackageVersion Include="Wiaoj.ObjectPool" Version="0.0.1-alpha.32" />
<PackageReference Include="Wiaoj.ObjectPool" />
paket add Wiaoj.ObjectPool --version 0.0.1-alpha.32
#r "nuget: Wiaoj.ObjectPool, 0.0.1-alpha.32"
#:package Wiaoj.ObjectPool@0.0.1-alpha.32
#addin nuget:?package=Wiaoj.ObjectPool&version=0.0.1-alpha.32&prerelease
#tool nuget:?package=Wiaoj.ObjectPool&version=0.0.1-alpha.32&prerelease
Wiaoj.ObjectPool
A high-performance, thread-safe, and fully asynchronous object pooling library for .NET.
Wiaoj.ObjectPool extends the capabilities of Microsoft.Extensions.ObjectPool by adding true asynchronous support, blocking/bounded pools, factory pattern integration, leak detection, 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). - 🏭 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. - 🔍 Leak Detection (Debug Only): Automatically detects if a leased object is garbage collected without being returned, pinpointing the exact stack trace of the leak.
- ✅ Return Validation: Optional validation logic to ensure objects are returned to the pool in a clean/valid state.
- 📦 Zero-Allocation Leasing: Uses a
readonly 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.
1. Register in DI
// Program.cs
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 async.
1. Register Async Pool
builder.Services.AddAsyncObjectPool<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: 4 Strategies
Wiaoj.ObjectPool offers flexibility in how you define object creation and cleanup.
1. The "Quick" Way (Lambdas)
Great for simple objects where logic fits in one line.
builder.Services.AddObjectPool<User>(
factory: () => new User(),
resetter: user => { user.Name = null; return true; }
);
2. 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.AddAsyncResettableObjectPool<SocketClient>();
3. 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 uses the registered factory!)
builder.Services.AddAsyncObjectPoolFromFactory<MyService>(
resetter: async svc => await svc.ResetAsync()
);
4. The "Full Control" Way (Custom Policy)
Best for complex dependencies where you need full control over the policy class.
// Register a class implementing IPoolPolicy<T> or IAsyncPoolPolicy<T>
builder.Services.AddAsyncObjectPool(new MyComplexPolicy());
⚙️ 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. It never blocks the thread. | CPU-bound objects (StringBuilder, buffers) where latency matters most. |
| Bounded | Throttled / Blocking. If the pool reaches MaximumRetained limit, GetAsync() will await until an object is returned. |
Limited resources (DB Connections, Throttled API Clients) to prevent system overload. |
🛡️ Developer Experience: Safety Nets
These features are active only in DEBUG builds and have zero performance impact in Release.
1. Leak Detection
If you forget to dispose a PooledObject, the library will catch it during Garbage Collection and log a fatal error with the stack trace.
Code with Bug:
var lease = pool.Lease(); // forgot 'using' or 'Dispose()'
// ... variable goes out of scope ...
Output Window:
[WIAOJ.OBJECTPOOLING LEAK DETECTED]
Object 'StringBuilder' leaked! It was collected without Dispose().
Origin:
at MyApp.Services.MyService.Method() in C:\Projects\MyApp\Service.cs:line 42
2. Return Validation
Ensure "dirty" objects don't pollute your pool.
builder.Services.AddObjectPool<List<string>>(options =>
{
#if DEBUG
options.OnReturnValidation = obj =>
{
var list = (List<string>)obj;
if (list.Count > 0) throw new InvalidOperationException("List was not cleared!");
};
#endif
});
📄 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.32)
- Wiaoj.Primitives (>= 0.0.1-alpha.32)
NuGet packages (2)
Showing the top 2 NuGet packages that depend on Wiaoj.ObjectPool:
| Package | Downloads |
|---|---|
|
Tyto
Package Description |
|
|
Tyto.Context
Package Description |
GitHub repositories
This package is not used by any popular GitHub repositories.
| Version | Downloads | Last Updated |
|---|---|---|
| 0.0.1-alpha.32 | 51 | 2/22/2026 |
| 0.0.1-alpha.31 | 46 | 2/22/2026 |
| 0.0.1-alpha.30 | 49 | 2/19/2026 |
| 0.0.1-alpha.29 | 44 | 2/17/2026 |
| 0.0.1-alpha.28 | 401 | 2/11/2026 |
| 0.0.1-alpha.27 | 69 | 2/7/2026 |
| 0.0.1-alpha.26 | 46 | 2/7/2026 |
| 0.0.1-alpha.25 | 46 | 2/7/2026 |
| 0.0.1-alpha.24 | 49 | 2/7/2026 |
| 0.0.1-alpha.23 | 48 | 1/30/2026 |
| 0.0.1-alpha.22 | 243 | 1/14/2026 |
| 0.0.1-alpha.21 | 51 | 1/13/2026 |
| 0.0.1-alpha.20 | 55 | 1/12/2026 |
| 0.0.1-alpha.19 | 53 | 1/12/2026 |
| 0.0.1-alpha.18 | 57 | 1/12/2026 |
| 0.0.1-alpha.17 | 59 | 1/6/2026 |
| 0.0.1-alpha.16 | 55 | 1/4/2026 |
| 0.0.1-alpha.15 | 54 | 1/2/2026 |
| 0.0.1-alpha.14 | 140 | 12/24/2025 |
| 0.0.1-alpha.13 | 719 | 12/17/2025 |