Язык программирования C#9 и платформа .NET5
До появления обобщений единственный способ решения проблемы, касающейся безопасности в отношении типов, предусматривал создание вручную специального класса (строго типизированной) коллекции. Предположим, что вы хотите создать специальную коллекцию, которая способна содержать только объекты типа
:Personnamespace IssuesWithNonGenericCollections{public class Person{public int Age {get; set;}public string FirstName {get; set;}public string LastName {get; set;}public Person(){}public Person(string firstName, string lastName, int age){Age = age;FirstName = firstName;LastName = lastName;}public override string ToString(){return $"Name: {FirstName} {LastName}, Age: {Age}";}}}Чтобы построить коллекцию, которая способна хранить только объекты
, можно определить переменную-членPersonвнутри класса по имениSystem.Collection.ArrayListи сконфигурировать все члены для оперирования со строго типизированными объектамиPeopleCollection, а не с объектами типаPerson. Ниже приведен простой пример (специальная коллекция производственного уровня могла бы поддерживать множество дополнительных членов и расширять абстрактный базовый класс из пространства именSystem.ObjectилиSystem.Collections):System.Collections.Specializedusing System.Collections;namespace IssuesWithNonGenericCollections{public class PersonCollection : IEnumerable{private ArrayList arPeople = new ArrayList();<b> // Приведение для вызывающего кода.</b>public Person GetPerson(int pos) => (Person)arPeople[pos];<b> // Вставка только объектов Person.</b>public void AddPerson(Person p){arPeople.Add(p);}public void ClearPeople(){arPeople.Clear();}public int Count => arPeople.Count;<b> // Поддержка перечисления с помощью foreach.</b>IEnumerator IEnumerable.GetEnumerator() => arPeople.GetEnumerator();}}Обратите внимание, что класс
реализует интерфейсPeopleCollection, который делает возможной итерацию в стилеIEnumerableпо всем элементам, содержащимся в коллекции. Кроме того, методыforeachиGetPerson()прототипированы для работы только с объектамиAddPerson(), а не растровыми изображениями, строками, подключениями к базам данных или другими элементами. Благодаря определению таких классов теперь обеспечивается безопасность в отношении типов, учитывая, что компилятор C# будет способен выявить любую попытку вставки элемента несовместимого типа. Обновите операторыPersonв файлеusing, как показано ниже, и поместите в конец текущего кода методProgram.cs:UserPersonCollection()using System;using System.Collections;using IssuesWithNonGenericCollections;// Операторы верхнего уровня в Program.csstatic void UsePersonCollection(){Console.WriteLine("***** Custom Person Collection *****\n");PersonCollection myPeople = new PersonCollection();myPeople.AddPerson(new Person("Homer", "Simpson", 40));myPeople.AddPerson(new Person("Marge", "Simpson", 38));myPeople.AddPerson(new Person("Lisa", "Simpson", 9));myPeople.AddPerson(new Person("Bart", "Simpson", 7));myPeople.AddPerson(new Person("Maggie", "Simpson", 2));<b> // Это вызовет ошибку на этапе компиляции!</b>// myPeople.AddPerson(new Car());foreach (Person p in myPeople){Console.WriteLine(p);}}Хотя специальные коллекции гарантируют безопасность в отношении типов, такой подход обязывает создавать (в основном идентичные) специальные коллекции для всех уникальных типов данных, которые планируется в них помещать. Таким образом, если нужна специальная коллекция, которая могла бы оперировать только с классами, производными от базового класса
, тогда придется построить очень похожий класс коллекции:Car