using System; using System.Collections.Generic; namespace Developpez.Dotnet.ComponentModel { /// /// Gestionnaire d'un pool d'objet générique /// /// Type des objets à placer dans le gestionnaire public class ParameterizedGenericPool { /// /// Conteneur contenant l'objet du pool /// public class GenericPoolItem : IDisposable { LinkedListNode node = null; /// /// Node utilisée pour rattacher l'objet au pool /// public virtual LinkedListNode Node { get { if (node == null) node = new LinkedListNode(this); return node; } set { node = value; } } /// /// Objet placé dans le Pool /// public virtual T Value { get; protected set; } /// /// Gestionnaire parent /// public virtual ParameterizedGenericPool Parent{get;protected set;} /// /// Initialise une nouvelle instance de conteneur /// /// Element à placer /// Gestionnaire parent public GenericPoolItem(T newItem, ParameterizedGenericPool parent) { Value = newItem; Parent = parent; Node = null; } /// /// Repasse l'objet d'un état "libéré" à une état "non libéré" /// public virtual void UnDispose() { disposed = false; } bool disposed = false; /// /// Destructeur /// ~GenericPoolItem() { if (Environment.HasShutdownStarted) return; if (Parent.CanAddItem && Parent.AppendItemToPool(Node)) { GC.ReRegisterForFinalize(this); } } /// /// Passe l'objet à un état "libéré" et le replace dans le pool d'objets /// public void Dispose() { if (!disposed) { disposed = true; if (Parent.AppendItemToPool(this)) { GC.SuppressFinalize(this); } } } } /// /// Méthode servant à la création d'un nouvel objet dans le pool /// /// Objet crée public delegate T CreateNewItemMethod(); /// /// Pool d'objets /// protected virtual LinkedList Pool { get; private set; } /// /// Nombre d'objets actuellement présents dans le pool /// public virtual int PoolCount { get { return Pool.Count; } } /// /// Rajoute un objet dans le pool /// /// Objet à rajouter /// true si l'opération a réussit, false sinon protected virtual bool AppendItemToPool(GenericPoolItem item) { lock (Pool) { if (CanAddItem) { Pool.AddFirst(item); return true; } else { return false; } } } /// /// Indique si l'état actuel du gestionnaire permet d'y rajouter un objet. /// (S'il y a déjà un nombre maximal d'éléments dans le pool, aucun ajout ne sera possible) /// public virtual bool CanAddItem { get { if (Pool.Count >= MaxCachedItemCount) return false; else return true; } } /// /// Rajoute un objet dans le pool /// /// Objet à rajouter /// true si l'opération a réussit, false sinon protected virtual bool AppendItemToPool(LinkedListNode item) { lock (Pool) { if (CanAddItem) { Pool.AddFirst(item); return true; } else return false; } } /// /// Renvoie un objet du pool /// /// Un objet du pool, ou null si aucun objet n'est disponible dans le pool protected virtual GenericPoolItem GetItemFromPool() { lock (Pool) { if (Pool.Count <= 0) return null; else { GenericPoolItem res = Pool.Last.Value; Pool.RemoveLast(); res.UnDispose(); return res; } } } /// /// Nombre d'objets initialement présents dans le pool /// public virtual int BaseCachedItemCount { get; protected set; } /// /// Nombre d'objets maximum dans le pool /// public virtual int MaxCachedItemCount { get; protected set; } /// /// Function servant à créer de nouveaux objets pour le pool /// protected virtual CreateNewItemMethod NewItemAllocator { get; set; } /// /// Crée une nouvel instance du gestionnaire de pool générique /// /// Objets alloués au démarrage /// Nombre maximum d'objets avant que ceux-ci ne soient relachés /// allocateur public ParameterizedGenericPool(int basePooledItemCount, int maxPooledItemCount, CreateNewItemMethod newItemAllocator) { if (newItemAllocator == null) throw new ArgumentNullException("newItemAllocator"); if (basePooledItemCount < 1) throw new ArgumentOutOfRangeException("basePooledItemCount"); if (maxPooledItemCount < basePooledItemCount) throw new ArgumentOutOfRangeException("maxPooledItemCount"); MaxCachedItemCount = maxPooledItemCount; BaseCachedItemCount = basePooledItemCount; NewItemAllocator = newItemAllocator; Pool = new LinkedList.GenericPoolItem>(); GenericPoolItem myItem; LinkedListNode newNode; for (int i = 0; i < basePooledItemCount; i++) { newNode = new LinkedListNode( myItem = new GenericPoolItem(NewItemAllocator.Invoke(), this)); myItem.Node = newNode; Pool.AddFirst(newNode); } } /// /// Obtient un objet à partir du pool, ou en crée un nouveau si aucun n'est disponible /// /// Un objet du pool, ou un nouvel objet si aucun n'est disponible public virtual GenericPoolItem ObtainItem() { return ObtainItem(true); } /// /// Obtient un objet dans le pool /// /// Si le pool est vide et que canCreateNew vaut true, un nouvel /// objet est crée. Sinon, null est renvoyé /// Objet du pool, ou null si aucun objet n'est disponible et canCreateNew vaut false public virtual GenericPoolItem ObtainItem(bool canCreateNew) { GenericPoolItem item = GetItemFromPool(); if (item != null || !canCreateNew) { return item; } else { item = InternalNewItem(); return item; } } /// /// Crée un nouvel objet pour le pool /// /// Nouvel objet crée protected virtual GenericPoolItem InternalNewItem() { return new GenericPoolItem(NewItemAllocator.Invoke(), this); } } /// /// Gestionnaire d'un pool d'objet générique. Les objets doivent avoir /// un constructeur sans paramètre.
/// Si aucun constructeur sans paramètre n'est possible, utilisez la classe ///
/// Type d'objet à gérer public class GenericPool : ParameterizedGenericPool where T : new() { /// /// Crée une nouvel instance du gestionnaire de pool générique.
/// Par défaut 1 objet est présent dans le pool et 10 au maximum peuvent être gérés ///
public GenericPool() : this(1, 10) { } /// /// Crée une nouvel instance du gestionnaire de pool générique /// /// Objets alloués au démarrage /// Nombre maximum d'objets avant que ceux-ci ne soient relachés public GenericPool(int startObjectCount, int maxObjectCount) : base(startObjectCount, maxObjectCount, new ParameterizedGenericPool.CreateNewItemMethod(delegate { return new T(); })) { } } }