Ответ
Да, в C# можно использовать произвольное количество универсальных параметров типа (type parameters), разделяя их запятыми в угловых скобках <>. Это применяется в классах, структурах, интерфейсах и методах.
Примеры:
-
Класс с двумя параметрами (аналог
KeyValuePair<TKey, TValue>):public class Result<TData, TError> { public bool IsSuccess { get; init; } public TData? Data { get; init; } public TError? Error { get; init; } public static Result<TData, TError> Success(TData data) => new() { IsSuccess = true, Data = data }; public static Result<TData, TError> Failure(TError error) => new() { IsSuccess = false, Error = error }; } // Использование: Result<Order, string> operationResult = Result<Order, string>.Success(new Order()); -
Метод с несколькими параметрами типа:
public TOutput Transform<TInput, TOutput>(TInput input, Func<TInput, TOutput> mapper) { return mapper(input); } // Использование: int number = 42; string text = Transform<int, string>(number, n => n.ToString()); -
Интерфейс с ограничениями (constraints) для разных параметров:
public interface IRepository<TEntity, TKey> where TEntity : class, IEntity<TKey> { TEntity? GetById(TKey id); void Add(TEntity entity); } // Реализация: public class UserRepository : IRepository<User, int> { /* ... */ }
Рекомендации:
- Именуйте параметры типа понятно (например,
TKey,TValue,TResult), особенно когда их много. - Используйте ограничения (
where), чтобы сделать код более типобезопасным и читаемым. - Хотя формальных ограничений нет, чрезмерное количество параметров (более 3-4) часто сигнализирует о сложности дизайна, который стоит пересмотреть.
Ответ 18+ 🔞
Смотри, в C# тебе никто не запрещает навешивать на свои классы, методы и прочую хуету сколько угодно дженерик-параметров. Просто пишешь их через запятую в этих самых угловых скобках <>, и всё, поехали. Работает везде — в классах, структурах, интерфейсах, методах.
Вот, смотри как это выглядит на практике:
-
Класс с двумя типами (типа самодельный
KeyValuePair):public class Result<TData, TError> { public bool IsSuccess { get; init; } public TData? Data { get; init; } public TError? Error { get; init; } public static Result<TData, TError> Success(TData data) => new() { IsSuccess = true, Data = data }; public static Result<TData, TError> Failure(TError error) => new() { IsSuccess = false, Error = error }; } // Используем: Result<Order, string> operationResult = Result<Order, string>.Success(new Order());Ну, тут логично же: один тип для удачного результата, другой — для описания косяка. Удобно, ёпта.
-
Метод, который тоже может быть с несколькими типами:
public TOutput Transform<TInput, TOutput>(TInput input, Func<TInput, TOutput> mapper) { return mapper(input); } // Ну и вызываем: int number = 42; string text = Transform<int, string>(number, n => n.ToString());Вообще красота — сам контролируешь, что на входе и что на выходе, компилятор потом не придерётся.
-
А вот интерфейс, где на каждый тип можно свои ограничения навесить:
public interface IRepository<TEntity, TKey> where TEntity : class, IEntity<TKey> { TEntity? GetById(TKey id); void Add(TEntity entity); } // Пишем реализацию: public class UserRepository : IRepository<User, int> { /* ... */ }Видишь? Говорим:
TEntityдолжен быть классом и реализовыватьIEntity<TKey>. АTKeyуже сам по себе, какой скажут. Чётко.
А теперь, блядь, важные моменты, чтобы не выстрелить себе в ногу:
- Имена давай нормальные. Не
T1,T2,T3— это пиздец как потом разбираться. ПишиTKey,TValue,TResult, чтобы было понятно, кто за что отвечает. Особенно когда их больше двух. - Ограничения (
where) — твой друг. Они не для галочки, они делают код безопаснее и понятнее. Компилятор заранее отсечёт тупые попытки подсунуть не тот тип. - И главное, не ебенись. Формально ограничений нет, можешь хоть 10 параметров написать. Но если у тебя их больше 3-4 — это уже не код, а какая-то абстрактная хуйня. Скорее всего, дизайн твоего класса или метода — говно, и его надо пересмотреть. Серьёзно, остановись и подумай, не усложняешь ли ты всё просто так.
В общем, инструмент мощный, но как любой инструмент — можно и по пальцам себе им въебать, если использовать как попало. Думай головой, и всё будет пучком.