ObjectOwner<T> Struct
A RAII (Resource Acquisition Is Initialization) wrapper for objects obtained from ObjectPool<T>.
Namespace
CryptoHives.Foundation.Memory.Pools
Inheritance
ValueType ? ObjectOwner<T>
Implements
IDisposable
Syntax
public readonly struct ObjectOwner<T> : IDisposable where T : class
Type Parameters
T - The type of object being pooled. Must be a reference type.
Overview
ObjectOwner<T> provides automatic return of pooled objects to their pool using the RAII pattern. When disposed, it automatically returns the object to the pool. This struct should be used with the using statement to ensure proper disposal.
⚠️ Important Warnings
- This is a struct - Avoid boxing by not casting to
IDisposable - Use with
using- Always use in ausingstatement or block - Don't store in fields - Keep in local scope only
- Don't copy - The struct will be copied, causing double-returns to pool
Properties
| Property | Type | Description |
|---|---|---|
Object |
T |
The pooled object obtained from the pool |
Constructors
| Constructor | Description |
|---|---|
ObjectOwner(ObjectPool<T> objectPool) |
Creates an owner by getting an object from the specified pool |
Methods
public void Dispose()
Returns the object to the pool. Called automatically when used with using.
Usage Examples
Basic Usage
using Microsoft.Extensions.ObjectPool;
var pool = new DefaultObjectPool<StringBuilder>(
new DefaultPooledObjectPolicy<StringBuilder>()
);
using var owner = new ObjectOwner<StringBuilder>(pool);
StringBuilder sb = owner.Object;
sb.Append("Hello");
sb.Append(" World");
Console.WriteLine(sb.ToString());
// StringBuilder automatically returned to pool when owner disposes
With Custom Pool Policy
public class StringBuilderPolicy : IPooledObjectPolicy<StringBuilder>
{
public StringBuilder Create() => new StringBuilder();
public bool Return(StringBuilder obj)
{
obj.Clear();
return true;
}
}
var pool = new DefaultObjectPool<StringBuilder>(new StringBuilderPolicy());
using var owner = new ObjectOwner<StringBuilder>(pool);
StringBuilder sb = owner.Object;
// Use sb...
Processing Collections
public List<int> ProcessData(IEnumerable<int> items)
{
var pool = new DefaultObjectPool<List<int>>(
new ListPolicy<int>()
);
using var owner = new ObjectOwner<List<int>>(pool);
List<int> list = owner.Object;
foreach (int item in items)
{
if (item > 0)
{
list.Add(item);
}
}
return new List<int>(list); // Return a copy, not the pooled list
}
Thread Safety
Thread-safe when used correctly (one owner per instance). The pool itself handles thread-safety.
Best Practices
DO: Use with using Statement
using var owner = new ObjectOwner<StringBuilder>(pool);
StringBuilder sb = owner.Object;
// Use sb...
// Automatically returned to pool
DO: Keep Scope Minimal
string result;
using (var owner = new ObjectOwner<StringBuilder>(pool))
{
StringBuilder sb = owner.Object;
sb.Append("Data");
result = sb.ToString();
} // Pool object returned here
return result;
⚠️ DON'T: Store in Fields
// Wrong!
public class BadExample
{
private ObjectOwner<StringBuilder> _owner; // Don't do this!
}
⚠️ DON'T: Return the Pooled Object
// Wrong!
public StringBuilder GetStringBuilder()
{
using var owner = new ObjectOwner<StringBuilder>(pool);
return owner.Object; // Object will be returned to pool!
}
// Correct: Return the result
public string GetString()
{
using var owner = new ObjectOwner<StringBuilder>(pool);
return owner.Object.ToString();
}
⚠️ DON'T: Box the Struct
// Wrong!
IDisposable disposable = new ObjectOwner<StringBuilder>(pool); // Boxing!
// Correct:
using var owner = new ObjectOwner<StringBuilder>(pool);
⚠️ DON'T: Copy the Struct
// Wrong!
var owner1 = new ObjectOwner<StringBuilder>(pool);
var owner2 = owner1; // Copy! Both will try to return to pool
owner1.Dispose();
owner2.Dispose(); // Double return!
// Correct: Use once
using var owner = new ObjectOwner<StringBuilder>(pool);
Common Use Cases
Temporary String Building
public string FormatData(params object[] values)
{
using var owner = new ObjectOwner<StringBuilder>(stringBuilderPool);
StringBuilder sb = owner.Object;
foreach (var value in values)
{
sb.Append(value);
sb.Append(' ');
}
return sb.ToString().TrimEnd();
}
Temporary Collections
public int[] FilterPositive(int[] values)
{
using var owner = new ObjectOwner<List<int>>(listPool);
List<int> list = owner.Object;
foreach (int value in values)
{
if (value > 0)
{
list.Add(value);
}
}
return list.ToArray();
}
Temporary Buffers
public byte[] ProcessData(byte[] input)
{
using var owner = new ObjectOwner<MemoryStream>(streamPool);
MemoryStream stream = owner.Object;
stream.Write(input, 0, input.Length);
// Process stream...
return stream.ToArray();
}
Performance Characteristics
- Construction: O(1) - gets object from pool
- Disposal: O(1) - returns object to pool
- Memory: No heap allocation (struct, no boxing)
Remarks
Why a Struct?
ObjectOwner<T> is a struct to avoid heap allocation. When used correctly with using, it provides zero-allocation resource management.
Comparison with Direct Pool Usage
// Without ObjectOwner (error-prone)
var obj = pool.Get();
try
{
// Use obj...
}
finally
{
pool.Return(obj);
}
// With ObjectOwner (safer, cleaner)
using var owner = new ObjectOwner<T>(pool);
T obj = owner.Object;
// Use obj...
See Also
© 2025 The Keepers of the CryptoHives