Чтение онлайн

ЖАНРЫ

Язык программирования C#9 и платформа .NET5
Шрифт:

}

}

Обратите внимание, что класс

PeopleCollection
реализует интерфейс
IEnumerable
, который делает возможной итерацию в стиле
foreach
по всем элементам, содержащимся в коллекции. Кроме того, методы
GetPerson
и
AddPerson
прототипированы для работы только с объектами
Person
, а не растровыми изображениями, строками, подключениями к базам данных или другими элементами. Благодаря определению таких классов теперь обеспечивается безопасность в отношении типов, учитывая, что компилятор C# будет
способен выявить любую попытку вставки элемента несовместимого типа. Обновите операторы
using
в файле
Program.cs
, как показано ниже, и поместите в конец текущего кода метод
UserPersonCollection
:

using System;

using System.Collections;

using IssuesWithNonGenericCollections;

// Операторы верхнего уровня в Program.cs

static 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));

// Это вызовет ошибку на этапе компиляции!

// myPeople.AddPerson(new Car);

foreach (Person p in myPeople)

{

Console.WriteLine(p);

}

}

Хотя специальные коллекции гарантируют безопасность в отношении типов, такой подход обязывает создавать (в основном идентичные) специальные коллекции для всех уникальных типов данных, которые планируется в них помещать. Таким образом, если нужна специальная коллекция, которая могла бы оперировать только с классами, производными от базового класса

Car
, тогда придется построить очень похожий класс коллекции:

using System.Collections;

public class CarCollection : IEnumerable

{

private ArrayList arCars = new ArrayList;

// Приведение для вызывающего кода.

public Car GetCar(int pos) => (Car) arCars[pos];

// Вставка только объектов Car.

public void AddCar(Car c)

{

arCars.Add(c);

}

public void ClearCars

{

arCars.Clear;

}

public int Count => arCars.Count;

// Поддержка перечисления с помощью foreach.

IEnumerator IEnumerable.GetEnumerator => arCars.GetEnumerator;

}

Тем

не менее, класс специальной коллекции ничего не делает для решения проблемы с накладными расходами по упаковке/распаковке. Даже если создать специальную коллекцию по имени
IntCollection
, которая предназначена для работы только с элементами
System.Int32
, то все равно придется выделять память под объект какого-нибудь вида, хранящий данные (например,
System.Array
и
ArrayList
):

public class IntCollection : IEnumerable

{

private ArrayList arInts = new ArrayList;

// Получение int (выполняется распаковка).

public int GetInt(int pos) => (int)arInts[pos];

// Вставка int (выполняется упаковка).

public void AddInt(int i)

{

arInts.Add(i);

}

public void ClearInts

{

arInts.Clear;

}

public int Count => arInts.Count;

IEnumerator IEnumerable.GetEnumerator => arInts.GetEnumerator;

}

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

Первый взгляд на обобщенные коллекции

Когда используются классы обобщенных коллекций, все описанные выше проблемы исчезают, включая накладные расходы на упаковку/распаковку и отсутствие безопасности в отношении типов. К тому же необходимость в создании специального класса (обобщенной) коллекции становится довольно редкой. Вместо построения уникальных классов, которые могут хранить объекты людей, автомобилей и целые числа, можно задействовать класс обобщенной коллекции и указать тип хранимых элементов. Добавьте в начало файла

Program.cs
следующий оператор
using
:

using System.Collections.Generic;

Взгляните на показанный ниже метод (добавленный в конец файла

Program.cs
), в котором используется класс
List<T>
(из пространства имен
System.Collection.Generic
) для хранения разнообразных видов данных в строго типизированной манере (пока не обращайте внимания на детали синтаксиса обобщений):

static void UseGenericList

{

Console.WriteLine("***** Fun with Generics *****\n");

// Этот объект List<> может хранить только объекты Person.

List<Person> morePeople = new List<Person>;

morePeople.Add(new Person ("Frank", "Black", 50));

Console.WriteLine(morePeople[0]);

// Этот объект ListO может хранить только целые числа.

Поделиться с друзьями: