Язык программирования C#9 и платформа .NET5
Роль параметров обобщенных типов
Обобщенные классы, интерфейсы, структуры и делегаты вы можете обнаружить повсюду в библиотеках базовых классов .NET Core, и они могут быть частью любого пространства имен .NET Core. Кроме того, имейте в виду, что применение обобщений далеко не ограничивается простым определением класса коллекции. Разумеется, в оставшихся главах книги вы встретите случаи использования многих других обобщений для самых разных целей.
На заметку! Обобщенным образом могут быть записаны только классы, структуры, интерфейсы и делегаты, но не перечисления.
Глядя на обобщенный элемент в документации по .NET Core или в браузере объектов Visual Studio, вы заметите пару угловых скобок с буквой или другой лексемой внутри. На рис. 10.1 показано окно браузера объектов Visual Studio, в котором отображается набор обобщенных элементов из пространства имен
, включающий выделенный классSystem.Collections.Generic.List<T>Формально эти лексемы называются параметрами типа, но в более дружественных к пользователю терминах на них можно ссылаться просто как на заполнители. Конструкцию
можно читать как "типа<Т>". Таким образом,Тможно прочитать как "IEnumerable<T>типаIEnumerable".ТНа заметку! Имя параметра типа (заполнитель) роли не играет и зависит от предпочтений разработчика, создавшего обобщенный элемент. Однако обычно имя
применяется для представления типов,TилиТКеу— для представления ключей иКилиTValue— для представления значений.VКогда вы создаете обобщенный объект, реализуете обобщенный интерфейс или вызываете обобщенный член, на вас возлагается обязанность по предоставлению значения для параметра типа. Многочисленные примеры вы увидите как в этой главе, так и в остальных материалах книги. Тем не менее, для начала рассмотрим основы взаимодействия с обобщенными типами и членами.
Указание параметров типа для обобщенных классов и структур
При создании экземпляра обобщенного класса или структуры вы указываете параметр типа, когда объявляете переменную и когда вызываете конструктор. Как было показано в предыдущем фрагменте кода, в методе
определены два объектаUseGenericList():List<T>// Этот объект List<> может хранить только объекты Person.List<Person> morePeople = new List<Person>();// Этот объект List<> может хранить только целые числа.List<int> moreInts = new List<int>();Первую строку приведенного выше кода можно трактовать как "список
объектовList<>, гдеТ— типТ" или более просто как "список объектов действующих лиц". После указания параметра типа обобщенного элемента изменить его нельзя (помните, что сущностью обобщений является безопасность в отношении типов). Когда параметр типа задается для обобщенного класса или структуры, все вхождения заполнителя (заполнителей) заменяются предоставленным значением.PersonЕсли вы просмотрите полное объявление обобщенного класса
в браузере объектов Visual Studio, то заметите, что заполнитель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>результат будет таким же, как если бы типPersonбыл определен следующим образом:List<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();
