I don\'t want to write my own because i\'m afraid i might miss something and/or rip off other people\'s work, so is there an ObjectPool (or similar) class existing in a library
UPDATE:
I'd also put forward BufferBlockBufferBlock
is that you can wait asynchronously for items to become available using the Post
ORIGINAL ANSWER
A while back I faced this problem and came up with a lightweight (rough'n'ready) threadsafe (I hope) pool that has proved very useful, reusable and robust:
public class Pool where T : class
{
private readonly Queue> asyncQueue = new Queue>();
private readonly Func createFunction;
private readonly HashSet pool;
private readonly Action resetFunction;
public Pool(Func createFunction, Action resetFunction, int poolCapacity)
{
this.createFunction = createFunction;
this.resetFunction = resetFunction;
pool = new HashSet();
CreatePoolItems(poolCapacity);
}
public Pool(Func createFunction, int poolCapacity) : this(createFunction, null, poolCapacity)
{
}
public int Count
{
get
{
return pool.Count;
}
}
private void CreatePoolItems(int numItems)
{
for (var i = 0; i < numItems; i++)
{
var item = createFunction();
pool.Add(item);
}
}
public void Push(T item)
{
if (item == null)
{
Console.WriteLine("Push-ing null item. ERROR");
throw new ArgumentNullException();
}
if (resetFunction != null)
{
resetFunction(item);
}
lock (asyncQueue)
{
if (asyncQueue.Count > 0)
{
var result = asyncQueue.Dequeue();
result.SetAsCompletedAsync(item);
return;
}
}
lock (pool)
{
pool.Add(item);
}
}
public T Pop()
{
T item;
lock (pool)
{
if (pool.Count == 0)
{
return null;
}
item = pool.First();
pool.Remove(item);
}
return item;
}
public IAsyncResult BeginPop(AsyncCallback callback)
{
var result = new AsyncResult();
result.AsyncCallback = callback;
lock (pool)
{
if (pool.Count == 0)
{
lock (asyncQueue)
{
asyncQueue.Enqueue(result);
return result;
}
}
var poppedItem = pool.First();
pool.Remove(poppedItem);
result.SetAsCompleted(poppedItem);
return result;
}
}
public T EndPop(IAsyncResult asyncResult)
{
var result = (AsyncResult) asyncResult;
return result.EndInvoke();
}
}
In order to avoid any interface requirements of the pooled objects, both the creation and resetting of the objects is performed by user supplied delegates: i.e.
Pool msPool = new Pool(() => new MemoryStream(2048), pms => {
pms.Position = 0;
pms.SetLength(0);
}, 500);
In the case that the pool is empty, the BeginPop/EndPop pair provide an APM (ish) means of retrieving the object asynchronously when one becomes available (using Jeff Richter's excellent AsyncResult
I can't quite remember why it is constained to T : class... there's probably none.