Язык программирования C#9 и платформа .NET5. Страница 202
Роль параметров обобщенных типов
Обобщенные классы, интерфейсы, структуры и делегаты вы можете обнаружить повсюду в библиотеках базовых классов .NET Core, и они могут быть частью любого пространства имен .NET Core. Кроме того, имейте в виду, что применение обобщений далеко не ограничивается простым определением класса коллекции. Разумеется, в оставшихся главах книги вы встретите случаи использования многих других обобщений для самых разных целей.
На заметку! Обобщенным образом могут быть записаны только классы, структуры, интерфейсы и делегаты, но не перечисления.
Глядя на обобщенный элемент в документации по .NET Core или в браузере объектов Visual Studio, вы заметите пару угловых скобок с буквой или другой лексемой внутри. На рис. 10.1 показано окно браузера объектов Visual Studio, в котором отображается набор обобщенных элементов из пространства имен
System.Collections.GenericList<T>
Формально эти лексемы называются параметрами типа, но в более дружественных к пользователю терминах на них можно ссылаться просто как на заполнители. Конструкцию
<Т>ТIEnumerable<T>IEnumerableТНа заметку! Имя параметра типа (заполнитель) роли не играет и зависит от предпочтений разработчика, создавшего обобщенный элемент. Однако обычно имя
TТКеуКTValueVКогда вы создаете обобщенный объект, реализуете обобщенный интерфейс или вызываете обобщенный член, на вас возлагается обязанность по предоставлению значения для параметра типа. Многочисленные примеры вы увидите как в этой главе, так и в остальных материалах книги. Тем не менее, для начала рассмотрим основы взаимодействия с обобщенными типами и членами.
Указание параметров типа для обобщенных классов и структур
При создании экземпляра обобщенного класса или структуры вы указываете параметр типа, когда объявляете переменную и когда вызываете конструктор. Как было показано в предыдущем фрагменте кода, в методе
UseGenericList()List<T>// Этот объект List<> может хранить только объекты Person.List<Person> morePeople = new List<Person>();// Этот объект List<> может хранить только целые числа.List<int> moreInts = new List<int>();Первую строку приведенного выше кода можно трактовать как "список
List<>ТТPersonЕсли вы просмотрите полное объявление обобщенного класса
List<T>Т// Частичное определение класса List<T>.namespace System.Collections.Generic{ public class List<T> : IList<T>, IList, IReadOnlyList<T> { ... public void Add(<b>T</b> item); public void AddRange(IEnumerable<<b>T</b>> collection); public ReadOnlyCollection<<b>T</b>> AsReadOnly(); public int BinarySearch(<b>T</b> item); public bool Contains(<b>T</b> item); public void CopyTo(<b>T</b>[] array); public int FindIndex(System.Predicate<<b>T</b>> match); public T FindLast(System.Predicate<<b>T</b>> match); public bool Remove(<b>T</b> item); public int RemoveAll(System.Predicate<<b>T</b>> match); public <b>T</b>[] ToArray(); public bool TrueForAll(System.Predicate<<b>T</b>> match); public <b>T</b> this[int index] { get; set; } }}В случае создания
List<T>PersonList<T>namespace System.Collections.Generic{ public class List<<b>Person</b>> : IList<<b>Person</b>>, IList, IReadOnlyList<<b>Person</b>> { ... public void Add(<b>Person</b> item); public void AddRange(IEnumerable<<b>Person</b>> collection); public ReadOnlyCollection<<b>Person</b>> AsReadOnly();