Ответ
Ограничения обобщенных типов задаются с помощью ключевого слова where. Они указывают компилятору, какие типы могут быть использованы в качестве аргументов типа, и предоставляют дополнительную информацию о этих типах внутри обобщенного кода.
Синтаксис и виды ограничений:
public class Repository<T> where T : class, IEntity, new()
{
// T должен быть ссылочным типом (class),
// реализовывать интерфейс IEntity,
// и иметь открытый конструктор без параметров (new()).
}
| Ограничение | Описание | Пример использования |
|---|---|---|
where T : struct |
T должен быть значимым типом (не-nullable). |
T может быть int, DateTime, Guid. Не может быть string или class. |
where T : class |
T должен быть ссылочным типом. |
T может быть string, List<int>, любой пользовательский class. |
where T : notnull (C# 8.0+) |
T должен быть типом, не допускающим null. |
Запрещает T? для ссылочных типов. Полезно в контексте nullable reference types. |
where T : unmanaged (C# 7.3+) |
T должен быть неуправляемым типом (не ссылочным и не содержащим ссылочных полей). |
T может быть int, double, struct только из примитивов. Используется для низкоуровневого кода (Span, указатели). |
where T : new() |
T должен иметь открытый конструктор без параметров. |
Позволяет создавать экземпляры: T item = new T(); |
where T : BaseClass |
T должен быть или наследоваться от указанного базового класса. |
Гарантирует доступ к членам BaseClass. |
where T : ISomeInterface |
T должен реализовывать указанный интерфейс. |
Гарантирует, что у T есть методы/свойства интерфейса. |
Практические примеры:
-
Ограничение для репозитория, работающего только с сущностями:
public interface IEntity { int Id { get; set; } } public class GenericRepository<T> where T : class, IEntity { public T GetById(int id) { /* ... */ } // Компилятор знает, что у T есть свойство Id. } -
Ограничение для фабрики, создающей объекты:
public static T CreateInstance<T>() where T : new() { return new T(); // Без ограничения new() эта строка не скомпилируется. } -
Ограничение для метода расширения, работающего с перечислениями:
public static string GetDescription<T>(this T value) where T : Enum // Ограничение на Enum (C# 7.3+) { // Метод доступен только для типов перечисления. return typeof(T).GetField(value.ToString())? .GetCustomAttribute<DescriptionAttribute>()?.Description; } // Использование: MyEnum.Value.GetDescription(); -
Несколько параметров типа с разными ограничениями:
public class Mapper<TFrom, TTo> where TFrom : class where TTo : class, new() { public TTo Map(TFrom source) { /* ... */ } }
Ограничения делают обобщенный код более безопасным, выразительным и производительным, предоставляя компилятору информацию для проверок и оптимизаций.