← Назад к вопросам

Какие знаешь коллекции?

1.3 Junior🔥 242 комментариев
#Коллекции и структуры данных

Комментарии (2)

🐱
deepseek-v3.2PrepBro AI6 апр. 2026 г.(ред.)

Ответ сгенерирован нейросетью и может содержать ошибки

Коллекции в C# и Unity

В C# и, соответственно, в Unity разработке, коллекции — это структуры данных для хранения и управления группами объектов. Они являются фундаментальной частью .NET Framework и условно делятся на обобщенные (generic), появившиеся с .NET 2.0, и необобщенные, которые сейчас считаются устаревшими, но знать их полезно для поддержки legacy-кода.

Я разделю ответ на основные категории, уделяя особое внимание коллекциям, наиболее релевантным для разработки игр на Unity, где критичны производительность и управление памятью.

Основные обобщенные коллекции (System.Collections.Generic)

Это наиболее используемые и типобезопасные коллекции.

  • List<T> — динамический массив. Это, пожалуй, самая часто используемая коллекция в Unity.
    *   **Преимущества:** Быстрый доступ по индексу (O(1)), удобные методы (`Add`, `Remove`, `Find`, `Sort`).
    *   **Недостатки:** Медленное удаление элементов из середины (O(n)), так как требует сдвига последующих элементов.
    *   **Использование в Unity:** Хранение списков объектов (враги, снаряды), результатов поиска (`Physics.RaycastAll` возвращает массив, который часто конвертируют в `List`).
```csharp
List<Enemy> enemies = new List<Enemy>();
enemies.Add(new Enemy("Orc"));
Enemy firstEnemy = enemies[0]; // Быстрый доступ
```
  • Dictionary<TKey, TValue> — коллекция пар "ключ-значение", основанная на хэш-таблице.
    *   **Преимущества:** Очень быстрый поиск, добавление и удаление по ключу (в среднем O(1)).
    *   **Недостатки:** Нет упорядоченности, большее потребление памяти, чем у `List`.
    *   **Использование в Unity:** Кэширование ресурсов (ключ — путь, значение — `GameObject` или `Sprite`), хранение состояния объектов по их ID.
```csharp
Dictionary<string, GameObject> prefabCache = new Dictionary<string, GameObject>();
prefabCache.Add("Player", Resources.Load<GameObject>("Prefabs/Player"));
```
  • Queue<T> — коллекция, работающая по принципу "первым пришел — первым вышел" (FIFO). Элементы добавляются в конец, а извлекаются из начала.
    *   **Использование в Unity:** Очередь команд, система сообщений или событий, порядок генерации объектов.
```csharp
Queue<PlayerCommand> commandQueue = new Queue<PlayerCommand>();
commandQueue.Enqueue(new MoveCommand());
PlayerCommand nextCommand = commandQueue.Dequeue();
```
  • Stack<T> — коллекция, работающая по принципу "последним пришел — первым вышел" (LIFO). Как стопка тарелок.
    *   **Использование в Unity:** Система отмены действий (Undo/Redo), обход графов (например, в AI), управление состояниями UI.
```csharp
Stack<GameState> stateHistory = new Stack<GameState>();
stateHistory.Push(GameState.Menu);
GameState previousState = stateHistory.Pop();
```
  • HashSet<T> — коллекция, содержащая только уникальные элементы, основанная на хэш-таблице. Оптимизирована для операций множества (объединение, пересечение).
    *   **Преимущества:** Очень быстрая проверка наличия элемента (`Contains` — O(1)).
    *   **Использование в Unity:** Проверка уникальности (например, список собранных уникальных предметов), удаление дубликатов из данных.

Специализированные коллекции для Unity (производительность)

В высоконагруженных игровых циклах стандартные коллекции иногда могут создавать проблемы с аллокацией памяти в куче (heap allocation), что провоцирует сборку мусора (GC) и просадки FPS.

  • Массивы (T[]): Это не коллекция в строгом смысле, но базовый тип. Используйте их, когда размер известен и фиксирован. Нулевые аллокации в куче, если используется пул.

    Enemy[] enemySquad = new Enemy[10]; // Аллокация только при создании
    
  • UnityEngine.Collections (Unity Burst & Jobs-Compatible): Для многопоточности в Job System и Burst Compiler.

    *   **`NativeArray<T>`:** Аналог безопасного массива, работающий в unmanaged памяти. Не вызывает GC, может использоваться в джобах.
    *   **`NativeList<T>`, `NativeHashMap<T>`:** Аналоги `List` и `Dictionary` для unmanaged кода.

  • Паттерн "Объектный пул (Object Pooling)": Это не готовая коллекция, а архитектурный паттерн, который почти всегда реализуется на основе List<T>, Stack<T> или массива. Вместо создания (Instantiate) и уничтожения (Destroy) объектов, мы переиспользуем их, что радикально снижает нагрузку на GC.
    // Упрощенный пример пула на основе Stack
    Stack<Bullet> bulletPool = new Stack<Bullet>();
    Bullet GetBullet() {
        return (bulletPool.Count > 0) ? bulletPool.Pop() : Instantiate(bulletPrefab);
    }
    void ReturnBullet(Bullet bullet) {
        bullet.gameObject.SetActive(false);
        bulletPool.Push(bullet);
    }
    

Устаревшие необобщенные коллекции (System.Collections)

Знать о них стоит, но в новом коде использовать не рекомендуется: ArrayList, Hashtable, Queue, Stack. Они работают с типом object, что требует боксинга для значимых типов и приводит к потере производительности и типобезопасности.

Критерии выбора коллекции в Unity

  1. Нужен быстрый доступ по индексу? -> List<T> или массив.
  2. Нужен быстрый поиск по уникальному ключу? -> Dictionary<TKey, TValue>.
  3. Важна уникальность элементов и быстрая проверка принадлежности? -> HashSet<T>.
  4. Работа с данными в порядке очереди или стека? -> Queue<T> или Stack<T>.
  5. Критична производительность и минимизация GC? -> Рассмотрите массивы, Object Pooling или NativeCollections для джобов.
  6. Работа в основном потоке с частыми изменениями? -> List<T> или Dictionary<TKey, TValue>.

Грамотный выбор коллекции — это не просто синтаксис, а прямое влияние на производительность и частоту срабатывания сборщика мусора в вашей игре. В Unity это один из ключевых навыков оптимизации.

Какие знаешь коллекции? | PrepBro