Приглашаю вас обсудить данный вопрос.
И так, условия задачи:
- Нужна коллекция элементов для описания, например, системы частиц (это может быть все что угодно). Такая штука в которой в среднем 60 раз в секунду добавляются и удаляются сотни элементов.
- Изменения в коллекции не должны влиять на сборку мусора.
- Нельзя использовать структуры! Только ссылочные типы.
- Запрещено создавать и удалять классы, за исключением первой инициализации.
- Физическое количество элементов в коллекции должно быть постоянным. Т.к. изменение длинны массива достаточно накладная операция, а количество элементов должно постоянно плавать, то подойдет подобие кеша. Ограничение - разработчику желательно четко знать максимально возможное количество элементов в такой коллекции. А это значит игра должна быть грамотно спроектирована. Хотя лазейку я оставлю.
Набросал вот такой черновик.
Базовый класс для элемента коллекции:
public class TElementConstLength { private int indexInCollection = -1; internal int IndexInCollection { get { return indexInCollection; } } internal void SetIndexInCollection(int i) { indexInCollection = i; } }
Базовый класс для коллекции:
public class TCollectionConstLength<T> where T : TElementConstLength, new() { private T[] elements; private int count = 0; /// <summary> /// Количество живых элементов /// </summary> public int Count { get { return count; } } private int end = -1; /// <summary> /// Инициализация колекции /// </summary> /// <param name="length">Длинна коллекции</param> public TCollectionConstLength(int length) { elements = new T[length]; } /// <summary> /// Доступ к элементу по индексу /// </summary> /// <param name="index">Индекс</param> /// <returns>Элемент</returns> public T this[int index] { get { return elements[index]; } } /// <summary> /// Выделение места под новый элемент /// </summary> /// <returns>Новый элемент</returns> public virtual T GetNew() // = Add { // если список полон, для режима отладки if(end == elements.Length - 1) Array.Resize(ref elements, elements.Length + 1); // end++; count++; // если не инициализирован элемент if(elements[end] == null) { elements[end] = new T(); elements[end].SetIndexInCollection(end); } // return elements[end]; } /// <summary> /// Очистка списка /// </summary> public void Clear() { end = -1; count = 0; } /// <summary> /// Удаление элемента по индексу /// </summary> /// <param name="index">Индекс</param> public virtual void Remove(int index) { // выход за пределы if(index < 0 || index > end) return; if(index < end) { // рокировка элементов T temp = elements[end]; elements[end] = elements[index]; elements[index] = temp; // рокировка индексов int i = elements[end].IndexInCollection; elements[end].SetIndexInCollection(elements[index].IndexInCollection); elements[index].SetIndexInCollection(i); } // уменьшаем список end--; count--; } /// <summary> /// Удаление элемента /// </summary> /// <param name="e">Элемент</param> public virtual void Remove(T e) { // проверка на соответствие ссылок (защита от тупости) if(e != elements[e.IndexInCollection]) return; Remove(e.IndexInCollection); } }
Вот пример для тестов:
using System; namespace CollectionConstLength { public class ElementTest : TElementConstLength { private string name; public string Name { get { return name; } set { name = value; } } public ElementTest() { } } class Program { static TCollectionConstLength<ElementTest> item; static void Main(string[] args) { item = new TCollectionConstLength<ElementTest>(5); ElementTest et; for(int i = 0; i < 5; i++) { et = item.GetNew(); et.Name = i.ToString(); } // Print(); // item.Remove(item[1]); Print(); // Console.ReadKey(); } static void Print() { Console.WriteLine("//--------------------------------"); for(int i = 0; i < item.Count; i++) { Console.WriteLine( string.Format("index - {0}; name - \"{1}\";", item[i].IndexInCollection, item[i].Name)); } Console.WriteLine("//--------------------------------"); } } }
Пример наращивания функционала через наследование:
- Расширенный класс элемента:
public class TUpdate : TElementConstLength { public virtual void Update() { } }
- Расширенный класс коллекции
public class TUpdateCollection<T> : TCollectionConstLength<T> where T : TUpdate, new() { public TUpdateCollection(int l) : base(l) { } public virtual void Update() { for(int i = 0; i < base.Count; i++) { base[i].Update(); } } }
Данный подход позволяет исключить сборку мусора и равномерно распределить нагрузку на процессор. Для каждого наследника от базового класса нужно добавить метод заполняющий поля данного класса, что делает процесс инициализации нового члена коллекции похожим на инициализацию структуры.
Давайте пообщаемся на эту тему.
Так же буду рад ссылкам на статьи с подобными темами и изысканиями.