Найти в Дзене

Ограничения в обобщениях C#

Это видео является заключительной частью главы про обобщения в языке программирования C# и в нем мы подробно разбираем, что такое ограничения в обобщениях C# , зачем нужен оператор where и как они могут дать программисту большую свободу. Также рассматриваем типичные ошибки и сложности при работе с обобщениями и пути их решения.

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

private static Boolean MethodTakingAnyType<T>(T o) {
T temp = o;
Console.WriteLine(o.ToString());
Boolean b = temp.Equals(o);
return b;
}

В этом случае T может быть любым типом: ссылочным, значимым, перечислением, интерфейсом, делегатом и т.д. И этот код будет корректен, потому что абсолютно любой тип поддерживает операции определенные в Object, так как унаследован от него. Рассмотрим другой метод

private static T Min<T>(T o1, T o2) {
if (o1.CompareTo(o2) < 0) return o1;
return o2;
}

Здесь точно также T может быть любым типом, но далеко не все типы поддерживают операции сравнения CompareTo. Поэтому этот код не будет компилироваться.

Получается, достаточно интересная ситуация, что для обобщений мы можем применять только операции определенные в object, что делает их не очень-то и полезными. Если бы все так и осталось, то применялись бы они чуть реже, чем никогда. НО! Решение есть. Этот механизм ограничений (constraints).

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

public static T Min<T>(T o1, T o2) where T : IComparable<T> {
if (o1.CompareTo(o2) < 0) return o1;
return o2;
}

Как ты видишь, здесь используется специальный оператор where, который говорит, что T обязан реализовывать интерфейс IComparable. Таким образом, компилятор может быть уверен, что переменная типа T реализует этот интерфейс, и позволяет использовать все операции определенные в этом интерфейсе.

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

Существует три основных вида ограничений:

  • Основное (primary)
  • Дополнительное (secondary)
  • Ограничение конструктора

Подробный разбор каждого из видов ограничений можно найти в видео.

Кроме того, рекомендую прочитать статью Сколько времени нужно, чтобы стать программистом? А также подписывайтесь на группу ВКонтакте, Telegram и YouTube-канал. Там еще больше полезного и интересного для программистов.

Наука
7 млн интересуются