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

Что такое Generics?

1.8 Middle🔥 231 комментариев
#C# и ООП

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

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

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

Generics в C# и Unity

Generics (дженерики или обобщённые типы) — это мощный механизм языка C#, позволяющий создавать классы, интерфейсы, методы и делегаты, которые работают с данными неопределённого типа. Этот тип указывается позже, при использовании generic-объекта, что обеспечивает безопасность типов и исключает необходимость приведения типов или использования базового класса object.

Основная цель и преимущества

Главная цель — создание типобезопасных и высокопроизводительных компонентов без дублирования кода. В Unity, где часто приходится работать с разными типами данных (Vector3, GameObject, int, string), Generics особенно полезны.

Ключевые преимущества:

  • Типобезопасность: Компилятор проверяет соответствие типов, предотвращая ошибки времени выполнения.
  • Улучшенная производительность: Избегается boxing/unboxing для структур (struct) и приведение типов.
  • Сокращение кода: Не нужно создавать отдельные реализации для каждого типа данных.
  • Повышение читаемости: Код становится более выразительным и понятным.

Пример простого Generic класса в Unity

Представьте, что вам нужен пул объектов для повторного использования, но вы хотите использовать его для разных типов: GameObject, Rigidbody или даже ваших собственных компонентов.

// Обобщённый класс пула объектов
public class ObjectPool<T> where T : MonoBehaviour
{
    private Queue<T> pool = new Queue<T>();
    private T prefab;

    public ObjectPool(T prefab, int initialSize)
    {
        this.prefab = prefab;
        for (int i = 0; i < initialSize; i++)
        {
            T obj = Instantiate(prefab);
            obj.gameObject.SetActive(false);
            pool.Enqueue(obj);
        }
    }

    public T GetObject()
    {
        if (pool.Count > 0)
        {
            T obj = pool.Dequeue();
            obj.gameObject.SetActive(true);
            return obj;
        }
        return Instantiate(prefab);
    }

    public void ReturnObject(T obj)
    {
        obj.gameObject.SetActive(false);
        pool.Enqueue(obj);
    }
}

// Использование для разных типов
ObjectPool<Enemy> enemyPool = new ObjectPool<Enemy>(enemyPrefab, 10);
ObjectPool<Bullet> bulletPool = new ObjectPool<Bullet>(bulletPrefab, 20);

Enemy newEnemy = enemyPool.GetObject(); // Тип возвращаемого значения - Enemy
Bullet newBullet = bulletPool.GetObject(); // Тип возвращаемого значения - Bullet

Ограничения (Constraints) where T : ...

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

// T должен быть классом MonoBehaviour
public class Repository<T> where T : MonoBehaviour

// T должен реализовывать интерфейс IDamageable
public class DamageSystem<T> where T : IDamageable

// T должен иметь конструктор
public class Factory<T> where T : new()

// T должен быть классом
public class Singleton<T> where T : class

// T должен быть структурой
public class Container<T> where T : struct

Generics в стандартных коллекциях Unity и C#

Чаще всего в Unity Generics встречаются в стандартных коллекциях, которые являются их идеальной демонстрацией:

  • List<T> — динамический массив элементов типа T.
  • Dictionary<TKey, TValue> — коллекция ключ-значение.
  • Queue<T> и Stack<T> — очереди и стеки.
// Использование List<T> для разных типов в Unity
List<Transform> childTransforms = new List<Transform>();
List<Material> materials = new List<Material>();
List<int> scores = new List<int>();

// До Generics использовался ArrayList (небезопасный, медленный)
ArrayList oldList = new ArrayList(); // Можно добавить любой объект
oldList.Add(10); // int
oldList.Add("строка"); // string
// При извлечении требуется приведение типа, возможны ошибки
int score = (int)oldList[0]; // Опасно! Если элемент не int, будет исключение.

Generics в методах

Generics можно применять не только к классам, но и к методам, что полезно для создания универсальных вспомогательных функций.

// Generic метод для поиска ближайшего объекта в списке
public static T FindNearest<T>(Vector3 position, List<T> objects) where T : MonoBehaviour
{
    T nearest = null;
    float minDistance = float.MaxValue;

    foreach (T obj in objects)
    {
        float distance = Vector3.Distance(position, obj.transform.position1);
        if (distance < minDistance)
        {
            minDistance = distance;
            nearest = obj;
        }
    }
    return nearest; // Возвращает конкретный тип T
}

// Использование
Enemy nearestEnemy = FindNearest(playerPosition, enemies);
HealthPack nearestPack = FindNearest(playerPosition, healthPacks);

Заключение

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

Что такое Generics? | PrepBro