Code/ObjectPool.cs
using System;
using System.Collections.Generic;
namespace ObjectPools;
public class ObjectPool<T> : IDisposable where T : class
{
///<summary>How many objects have been created.</summary>
public int ObjectCountAll => _objectCountAll;
///<summary>How many objects are currently in the pool.</summary>
public int PoolCount => _pool.Count;
private readonly List<T> _pool;
private readonly Func<T> _onCreate;
private readonly Action<T> _onGet;
private readonly Action<T> _onRelease;
private readonly Action<T> _onDestroy;
private readonly bool _collectionCheck;
private readonly int _maxAmount;
private int _objectCountAll;
/// <param name="defaultCapacity">The default capacity of the pool.</param>
/// <param name="maxAmount">The max amount of items that the pool can hold before it starts to destroy them.</param>
/// <param name="collectionCheck">A check to make sure an item isn't released to the pool more than once.</param>
public ObjectPool(Func<T> onCreate, Action<T> onGet = null, Action<T> onRelease = null, Action<T> onDestroy = null, int defaultCapacity = 10, int maxAmount = 10000, bool collectionCheck = true)
{
if (onCreate == null)
{
Log.Error(nameof(onCreate) + " can't be null!");
return;
}
if (maxAmount <= 0)
{
Log.Error(nameof(maxAmount) + " can't be 0 or less!");
return;
}
_pool = new(defaultCapacity);
_onCreate = onCreate;
_onGet = onGet;
_onRelease = onRelease;
_onDestroy = onDestroy;
_collectionCheck = collectionCheck;
_maxAmount = maxAmount;
}
/// <summary>Creates items and adds them to the pool.</summary>
/// <param name="amount">How many items to add to the pool.</param>
/// <param name="useOnRelease">If the created item should go through the OnRelease function after being created.</param>
public void Prewarm(int amount, bool useOnRelease = true)
{
if (_pool.Count < _maxAmount)
{
for (int i = 0; i < amount; i++)
{
T item = _onCreate();
if (useOnRelease)
{
_onRelease?.Invoke(item);
}
_pool.Add(item);
_objectCountAll++;
}
}
}
///<summary>Get an item from the pool.</summary>
public T Get()
{
T item = null;
if (_pool.Count > 0)
{
item = _pool[^1];
_pool.RemoveAt(_pool.Count - 1);
}
else
{
item = _onCreate();
_objectCountAll++;
}
_onGet?.Invoke(item);
return item;
}
///<summary>Give back an item to the pool</summary>
public void Release(T item)
{
if (_collectionCheck && _pool.Count > 0 && _pool.Contains(item))
{
Log.Error("Trying to release an item that's already in the pool!");
return;
}
_onRelease?.Invoke(item);
if (PoolCount < _maxAmount)
{
_pool.Add(item);
}
else
{
_objectCountAll--;
_onDestroy?.Invoke(item);
}
}
public void Dispose()
{
if (_onDestroy != null)
{
for (int i = _pool.Count - 1; i >= 0; i--)
{
_onDestroy(_pool[i]);
}
}
_pool.Clear();
_objectCountAll = 0;
}
}