Коллекции
Пространство имен System.Collections Наиболее простой вариант набора элементов это массив System. Array. Он уже обладает весьма полезными встроенными функциями, которые позволяют производить операции сортировки, клонирования, перечисления и расстановки элементов в обратном порядке. Однако создатели библиотеки базовых классов С# приготовили для нас большое количества встроенных типов, которые позволят сэкономить массу времени при решении часто встречающихся задач. Все эти типы, как следует из самого названия System.Collections, предназначены для работы с наборами элементов.
Первое, о чем необходимо сказать, это то что в System.Collections определен набор стандартных интерфейсов. Кроме того, эти же интерфейсы определены в большинстве классов System.Collections. Краткий перечень наиболее важных интерфейсов пространства имен System.ColIections представлен в таблице. Но сначала поговорим об «отношениях» этих интерфейсов. Многие интерфейсы объединены в иерархии, когда как некоторые существуют отдельно и независимо от остальных. Отношения наследования представлены на рисунке.
Схема отношений наследования
Теперь приведем краткий перечень интерфейсов…
Интерфейсы пространства имен System.Collections ИнтерфейсНазначение ICollectionОпределяет общие характеристики (например, только для чтения и т. д.) для класса-набора элементов IComparerПозволяет сравнивать два объекта IDictionaryПозволяет представлять содержимое объекта в виде пар имя значение IListОбеспечивает методы для добавления, удаления и индексирования элементов в списке объектов
Интерфейсы пространства имен System.Collections ИнтерфейсНазначение IDictionary Enumerator Используется для нумерации содержимого объекта, поддерживающего IDictionary lEnumerableВозвращает интерфейс lEnumerator для указанного объекта lEnumeratorОбычно используется для поддержки конструкции foreach в отношении объектов IHashCodeProviderВозвращает хэш-код для реализации типа с применением выбранного пользователем алгоритма хэширования
Теперь представим наиболее используемые классы…
Классы System.Collections КлассНазначение Важнейшие из реализованных интерфейсов ArrayList Динамически изменяющий свой размер массив объектов IList, ICollection, lEnumerable Hashtable Представляет набор взаимосвязанных ключей и значений, основанных на хэш-коде ключа. IDictionary, ICollection, lEnumerable и ICIoneable. Кроме того, у типов, которые предназначены для хранения в Hashtable, всегда должен быть замещен метод System, Object- GetHashCodeQ Queue Стандартная очередь, реализованная по принципу FIFO (first-in-first-out, « первым пришел, первым ушел » ) ICollection, ICIoneable и lEnumerable
Классы System.Collections КлассНазначение Важнейшие из реализованных интерфейсов Sorted List Аналогично словарю, однако к элементам можно также обратиться по их порядковому номеру(индексу) IDictiOtiary, ICollection, lEnumerable и ICIoneable Stack Очередь, реализованная по принципу UFO (last-in-first-out, « последним пришел, первым ушел » ), обеспечивающая возможности по проталкиванию данных в стек, выталкиванию данных из стека и считыванию данных ICollection и lEnumerable
Пространство имен System.Collections.Specialized Если ни один из классов, представленных в пространстве имен System.Collection, вам не подходит, есть смысл заглянуть в пространство имен System.Collections.Specialized. В этом пространстве имен определен свой набор типов для работы с наборами элементов. Как видно из названия пространства имен, эти типы предназначены для специальных случаев. В качестве примера можно назвать типы StringDIctionary и ListDictionary, которые специальным образом реализуют интерфейс IDictionary.
Применение ArrayList При ближайшем рассмотрении классов, определенных в пространстве имен System.Collections, выясняется, что они обладают очень схожей функциональностью и реализуют одни и те же интерфейсы. Поэтому вместо того, чтобы углубляться в подробности реализации каждого из классов, мы подробно разберем применение лишь одного из них System.Collections.ArrayList,
Для того чтобы воспользоваться возможностями ArrayList, мы применим не классическое наследование, а модель включения - делегирования, когда класс ArrayList будет вложен внутрь созданного ранее класса Cars). Фактически единственное, что мы должны сделать, реализовать в Cars набор открытых методов, которые будут передавать вызовы на выполнение различных действий (делегировать) внутреннему классу carList, производному от ArrayList.
Выглядеть всё это будет так: //Нам больше не нужно реализовывать lEnumerator - все уже сделано за нас в ArrayList public class Cars: IEnumerable { // Это - тот самый внутренний класс, который и будет делать всю работу private ArrayList carList: // Создаем объект класса carList при помощи конструктора Cars public Cars() {carLlst = new ArrayLis():} // Реализуем нужные нам методы для приема вызовов извне и передачи их carList // Метод для вставки объекта Саг public void AddCar(Car с) { carList.Add(c); } // Метод для удаления объекта Саг public void RemoveCar(int carToRemove) { carList.RernoveAt(carToRemove); }
// Свойство, возвращающее количество объектов Car public int CarCount { get { return carList.Count; } } // Метод для очистки объекта - удаления всех объектов Саг public void ClearAllCarsO { carList.Clear(); } // Метод. который отвечает на вопрос - есть ли уже в наборе такой объект Саг public bool CarlsPresent(Car с) { return carList.Contains(c); } // А все, что связано с реализацией lEnumerator, мы просто перенаправляем в carList public lEnumerator GetEnumerator() { return carList.GetEnumerator(); } }
А теперь покажем, что такое объявление проще использовать… public static void Main() { Cars carLot = new Cars(); // Чтобы было с чем работать, добавляем несколько объектов Саг carLot.AddCar( new Саг("Jasper", )); carLot.AddCar( new Car("Mandy, )); carLot.AddCar( new CarCPorker". 90, 90)); carLot.AddCar( new CarC'Jimbo", 40, 4)); // Выводим информацию о каждом классе при помощи конструкции foreach Console.WriteLine('You have {0} in the lot; \n". carLot.CarCount); foreach (Саг с in carLot) { Console.WriteLine('Name: {0}', c.PetName): Console.WriteLine('Max speed; {0}\n". c.MaxSpeed); }
// Удаляем одну из машин carLot.RemoveCar(): Console.WriteLine('You have {0} in the lot.Xn, carLot.Car-Count): // Добавляем еще одну машину и проверяем ее наличие в наборе Саг temp = new Car("Zippy", ); CarLot.AddCar(temp); If(carLot.CarlsPresent(temp)) Console.WriteLine(ternp.PetName + " is already in the lot."); car-Lot.ClearAllCar(): Console.WriteLine('You have {0} In the 1ot.\n", carLot.Car-Count"}; }
Результат В результате работы программы мы получим:
Вместо заключения… Теперь настало время ответить на вопрос а почему нельзя просто произвести класс Cars от ArrayList? Зачем потребовалось все усложнять и создавать внутри Cars вспомогательный класс и дополнительные методы? Ответ очень прост ArrayList сам по себе работает с любыми объектами. Это значит, что при использовании классического наследования класс Cars можно было бы заполнить объектами абсолютно любых типов С#.