Общий пул объектов

Можно ли создать общий пул объектов, который создает внутри него новые объекты? Плюс было бы неплохо, если бы создание этого объекта могло получать параметры.

    public interface IPoolable
    {
        void Dispose();
    }


    public class ObjectPool<T> where T : IPoolable
    {
        private List<T> pool;

        public T Get()
        {
            if(pool.count > 0)
            {
                return pool.Pop();
            }
            else
            {
                return new T(); //  <- How to do this properly?
            }
        }
    }

    public class SomeClass : IPoolable
    {
        int id;

        public SomeClass(int id)
        {
            this.id = id;
        }

        public void Dispose()
        {

        }
    }

    public class OtherClass : IPoolable
    {
        string name;
        int id;

        public OtherClass(string name, int id)
        {
            this.name = name;
            this.id = id;
        }

        public void Dispose()
        {

        }
    }

Таким образом, чтобы его можно было использовать вот так, если бы он мог получать параметры.

SomeClass a = myPool.Get(2);
OtherClass b = myOtherPool.Get("foo", 4);

Или это тоже было бы хорошо, если бы параметры были невозможны.

SomeClass a = myPool.Get();
a.id = 2;
OtherClass b = myOtherPool.Get();
b.name = "foo";
b.id = 4;

person MathiasDG    schedule 22.06.2016    source источник
comment
Вы в основном говорите о фабрике? Это обычный объектно-ориентированный шаблон. Объединение может быть его компонентом, но, как правило, создание экземпляра объекта происходит очень быстро, и в объединении нет необходимости, если в конструкторе не нужно выполнять много настроек объекта. Единственный способ сделать его действительно универсальным - это использовать отражение для создания экземпляров объектов.   -  person itsme86    schedule 22.06.2016
comment
Он говорит о поддержании пула уже созданных объектов и создании нового экземпляра только в том случае, если пул пуст, вроде того, как пул соединений работает только в общем, а не только в соединениях. Я согласен с тем, что для легких объектов это немного бесполезно.   -  person Kevin    schedule 22.06.2016


Ответы (3)


Вы можете использовать Activator.CreateInstance Method.

public static object CreateInstance(
    Type type,
    params object[] args
)

Нравится

return (T)Activator.CreateInstance(typeof(T), id);

Однако невозможно указать, что тип должен предоставлять конструктор с аргументом; ни в объявлении интерфейса, ни в ограничениях универсального типа, ни в наследовании классов.

person Olivier Jacot-Descombes    schedule 22.06.2016

Вы можете сделать что-то вроде этого:

public class ObjectPool<T>
{
    private Queue<T> _pool = new Queue<T>();

    private const int _maxObjects = 100;  // Set this to whatever

    public T Get(params object[] parameters)
    {
        T obj;

        if (_pool.Count < 1)
            obj = (T)Activator.CreateInstance(typeof(T), parameters);
        else
            obj = _pool.Dequeue();

        return obj;
    }

    public void Put(T obj)
    {
        if (_pool.Count < _maxObjects)
            _pool.Enqueue(obj);
    }
}
person itsme86    schedule 22.06.2016
comment
Что будет делать. Спасибо! - person MathiasDG; 22.06.2016

Я искал нечто подобное и наткнулся на это:

public class ObjectPool<TObject>
    {
        private int maxPoolSize;
        private SpinLock poolLock;
        private Dictionary<Type, Stack<TObject>> poolCache;
        private Func<TObject> factory;

        public ObjectPool(int poolSize)
        {
            this.maxPoolSize = poolSize;
            this.poolLock = new SpinLock(false);
            this.poolCache = new Dictionary<Type, Stack<TObject>>();
        }

        public ObjectPool(int poolSize, Func<TObject> factory) : this(poolSize)
        {
            this.factory = factory;
        }

        public T Rent<T>() where T : TObject
            => (T)this.Rent(typeof(T));

        public TObject Rent(Type type)
        {
            bool lockTaken = false;
            Stack<TObject> cachedCollection;
            this.poolLock.Enter(ref lockTaken);

            try
            {
                if (!this.poolCache.TryGetValue(type, out cachedCollection))
                {
                    cachedCollection = new Stack<TObject>();
                    this.poolCache.Add(type, cachedCollection);
                }
            }
            finally
            {
                if (lockTaken)
                {
                    this.poolLock.Exit(false);
                }
            }

            if (cachedCollection.Count > 0)
            {
                TObject instance = cachedCollection.Pop();
                if (instance != null)
                    return instance;
            }

            // New instances don't need to be prepared for re-use, so we just return it.
            if (this.factory == null)
            {
                return (TObject)Activator.CreateInstance(type);
            }
            else
            {
                return this.factory();
            }
        }

        public void Return(TObject instanceObject)
        {
            Stack<TObject> cachedCollection = null;
            Type type = typeof(TObject);

            bool lockTaken = false;
            this.poolLock.Enter(ref lockTaken);
            try
            {
                if (!this.poolCache.TryGetValue(type, out cachedCollection))
                {
                    cachedCollection = new Stack<TObject>();
                    this.poolCache.Add(type, cachedCollection);
                }

                if (cachedCollection.Count >= this.maxPoolSize)
                {
                    return;
                }

                cachedCollection.Push(instanceObject);
            }
            finally
            {
                if (lockTaken)
                {
                    this.poolLock.Exit(false);
                }
            }
        }
    }

Это очень хорошая реализация, которую я бессовестно украл здесь

Он поддерживает объединение любых объектов, наследуемых от параметра универсального типа.

person Matthew Goulart    schedule 26.07.2018