Какие коллекции используешь?
Комментарии (2)
Ответ сгенерирован нейросетью и может содержать ошибки
Используемые коллекции в Unity/C# разработке
В Unity-разработке я активно использую весь спектр коллекций из System.Collections, System.Collections.Generic и System.Collections.Concurrent пространств имен, выбирая их в зависимости от конкретных задач производительности, потокобезопасности и семантики данных.
Основные типы коллекций
1. Generic коллекции (наиболее часто используемые):
// List<T> - основная рабочая лошадка для динамических массивов
List<GameObject> enemies = new List<GameObject>();
enemies.Add(enemyPrefab);
enemies.RemoveAt(0);
// Dictionary<TKey, TValue> - для быстрого поиска по ключу
Dictionary<string, PlayerData> players = new Dictionary<string, PlayerData>();
players["player1"] = new PlayerData();
if (players.ContainsKey("player2")) { /* ... */ }
// HashSet<T> - для уникальных элементов и операций с множествами
HashSet<int> collectedItems = new HashSet<int>();
collectedItems.Add(101);
bool isNew = collectedItems.Add(101); // false, элемент уже существует
// Queue<T> и Stack<T> - для FIFO и LIFO структур
Queue<Action> actionQueue = new Queue<Action>();
Stack<Transform> undoStack = new Stack<Transform>();
2. Специализированные Unity-коллекции:
// Массивы - для фиксированных данных, известных на этапе компиляции
public GameObject[] waypoints; // Назначается в инспекторе
// Unity-специфичные коллекции для оптимизации
using Unity.Collections; // Для низкоуровневых операций
using UnityEngine.Pool; // Object Pooling для оптимизации инстанциирования
Критерии выбора коллекций
Я выбираю коллекции по следующим параметрам:
-
Частота добавления/удаления элементов:
- Частые изменения:
List<T>илиLinkedList<T> - Редкие изменения: массивы
- Частые изменения:
-
Необходимость поиска:
- По ключу:
Dictionary<TKey, TValue>(O(1) в среднем) - По значению:
HashSet<T>илиList<T>с бинарным поиском после сортировки
- По ключу:
-
Порядок элементов:
- Важен порядок добавления:
List<T>,Queue<T> - Нужен доступ к обоим концам:
LinkedList<T> - LIFO/FIFO:
Stack<T>/Queue<T>
- Важен порядок добавления:
-
Потокобезопасность:
- Многопоточность: коллекции из
System.Collections.Concurrent - Один поток: стандартные generic-коллекции
- Многопоточность: коллекции из
Паттерны использования в Unity
Для GameObject и компонентов:
// Кэширование компонентов
private Dictionary<Type, Component> _componentCache = new Dictionary<Type, Component>();
public T GetCachedComponent<T>() where T : Component
{
Type type = typeof(T);
if (!_componentCache.ContainsKey(type))
{
_componentCache[type] = GetComponent<T>();
}
return (T)_componentCache[type];
}
Для оптимизации в Update-методах:
// Использование Capacity для избежания аллокаций
List<Vector3> positions = new List<Vector3>(100);
void Update()
{
positions.Clear(); // Переиспользование коллекции
// Заполнение positions
}
Для событий и делегатов:
private HashSet<Action> _eventHandlers = new HashSet<Action>();
// HashSet предотвращает дублирование подписчиков
Производительность и память
В performance-critical секциях (Update, FixedUpdate, рендеринг) я придерживаюсь правил:
- Избегаю аллокаций в циклах через предварительное выделение памяти (
Capacity) - Использую struct-коллекции из
Unity.Collectionsдля Burst-компиляции - При работе с большими данными выбираю массивы вместо List для уменьшения оверхеда
- Для частых поисков использую Dictionary, даже если нужно поддерживать порядок (комбинирую с List)
Пример оптимизации:
// Плохо: аллокация в каждом кадре
List<Enemy> GetActiveEnemies()
{
return new List<Enemy>(_allEnemies.Where(e => e.IsActive));
}
// Хорошо: переиспользование коллекции
private List<Enemy> _activeEnemiesCache = new List<Enemy>(50);
List<Enemy> GetActiveEnemiesOptimized()
{
_activeEnemiesCache.Clear();
foreach (var enemy in _allEnemies)
{
if (enemy.IsActive)
_activeEnemiesCache.Add(enemy);
}
return _activeEnemiesCache;
}
Выбор коллекции — это всегда компромисс между скоростью операций, потреблением памяти и удобством использования. В Unity особенно важен учет сборщика мусора, поэтому я предпочитаю структуры данных, минимизирующие аллокации в куче.