Коллекция это совокупность объектов, с которыми можно совершать различные действия. Если требуется снизить трудоемкость разработки структур данных именно коллекции приходят на помощь.
Элементы объединяют в коллекции по какому-либо признаку и потом используют их. Это нужно для того, чтобы не приходилось писать код для каждого элемента отдельно. Ведь можно написать один блок, который будет управлять всеми элементами сразу.
Элементы в коллекциях можно изменять, их можно удалять, а также добавлять
новые. Размерность коллекций при этом изменяется автоматически, поэтому ее не
нужно переопределять, что значительно облегчает работу. В этой работе я
рассмотрю основные виды и типы коллекций, а также интерфейсы, используемые
коллекциями. Приведу примеры использования коллекций и правила их реализации.
1. Коллекции в .Net
В .NET коллекция представляет собой объект. Даже самый примитивный массив является объектом. Массив можно создать, у него есть методы и свойства, и как все другие классы, он является ссылочным типом.
Ниже представлен пример использования простой коллекции. Сначала
создается список строк, а затем просматриваются строки с помощью оператора
foreach.
Рассмотрим виды и типы коллекций.
.1 Виды коллекций
Коллекция - некоторая конечная совокупность объектов, с которой можно совершать те или иные действия. Так, обычно по отношению к коллекции можно осуществлять перебор ее элементов. Физические реализации коллекций могут быть совершенно разными. Во Framework Class Library (FCL) коллекции в основном размещаются в пространстве имен System.Collections. Их список приведен в таблице 1. [1]
интерфейс оператор коллекция итератор
Таблица 1.1 - Коллекции, доступные в .NET Framework
|
Тип коллекции |
Назначение |
|
Встроенные массивы |
Обычные массивы, поддерживаемые CLR (Common Language Runtim) напрямую. В совестимых с CLR языках они являются полноценными объектами. |
|
ArrayList |
Является реализацией абстракции списка на базе массива, Позволяет динамически изменять размер, добавлять и удалять элементы. По сути, динамический массив, позволяющий хранить ссылки на объекты. |
|
Hashtable |
Реализует абстракцию «словарь» (Dictionary, коллекцию пар «ключ-значение») на основе алгоритма хэш-таблицы. |
|
SortedList |
Реализация абстракции словаря и списка на базе сортированного массива. |
|
Stack |
Реализует абстракцию «стек» - коллекцию, позволяющую осуществлять доступ к элементам по принципу FILO (First In - Last Out, первым пришел - последним ушел). В качестве хранилища используется массив. |
|
Queue |
Реализует абстракцию «очередь» - коллекцию, позволяющую осуществлять доступ к элементам по принципу FIFO (First In - First Out, первым пришел - первым ушел). В качестве хранилища используется массив. |
|
BitArray |
Позволяет создавать битовые массивы и управлять ими. |
В .NET Framework массив не относится к числу коллекций, хотя по своему предназначению массивы тоже являются коллекциями. Массивы отделены от коллекций потому, что они поддерживаются средой исполнения непосредственно. [1]
Типы коллекций.
Главное преимущество коллекций заключается в том, что они стандартизируют обработку групп объектов в программе. Все коллекции разработаны на основе набора четко определенных интерфейсов. Некоторые встроенные реализации таких интерфейсов, в том числе ArrayList, Hashtable, Stack и Queue, могут применяться в исходном виде и без каких-либо изменений. Имеется также возможность реализовать собственную коллекцию, хотя потребность в этом возникает крайне редко. [2]
В среде .NET Framework поддерживаются пять типов коллекций: необобщенные, специальные, с поразрядной организацией, обобщенные и параллельные. [2]
Необобщенные коллекции.
Необобщенные или простые коллекции определены в пространстве имен System.Collections. Их особенность состоит в том, что их функциональность, функциональные возможности описываются в интерфейсах, которые также находятся в этом пространстве имен. [3]
Специальные коллекции.
Оперируют данными конкретного типа или же делают это каким-то особым образом. Например, имеются специальные коллекции для символьных строк, а также специальные коллекции, в которых используется однонаправленный список. Специальные коллекции объявляются в пространстве имен System.Collections.Specialized. [2]
Поразрядная коллекция.
В прикладном интерфейсе Collections API определена одна коллекция с поразрядной организацией - это BitArray. Коллекция типа BitArray поддерживает поразрядные операции, т.е. операции над отдельными двоичными разрядами, например. И, ИЛИ, исключающее ИЛИ, а, следовательно, она существенно отличается своими возможностями от остальных типов коллекций. Коллекция типа BitArray объявляется в пространстве имен System.Collections. [2]
Обобщенные коллекции.
Классы обобщенных коллекций находятся в пространстве имен System.Collections.Generic. Функционал коллекций также по большей части описывается в обобщенных интерфейсах. [3]
Обеспечивают обобщенную реализацию нескольких стандартных структур данных, включая связные списки, стеки, очереди и словари. Такие коллекции являются типизированными в силу их обобщенного характера. Это означает, что в обобщенной коллекции могут храниться только такие элементы данных, которые совместимы по типу с данной коллекцией. Благодаря этому исключается случайное несовпадение типов. [2]
Параллельные коллекции.
Поддерживают многопоточный доступ к коллекции. Это обобщенные коллекции, определенные в пространстве имен System.Collections.Concurrent.
В листинге 1 (см. Приложение А) представлен пример использования коллекций, работы с элементами, добавление и удаление некоторых элементов. Приведенный пример взят из источника [3]. Результат работы этой программы представлен на рисунке А.1 в приложении А.
В этой программе используются две коллекции: необобщенная - ArrayList и обобщенная - List.
objectList = new ArrayList() { 1, 2, "string", 'c',
2.0f };<string> countries = new List<string>() {
"Россия", "США", "Великобритания",
"Китай" };
Большинство коллекций поддерживают добавление элементов. В данном примере добавление производится методом Add, но для других коллекций название метода может отличаться. [3]
.Add("string2");
Также большинство коллекций реализуют удаление, в этом примере удаление производится с помощью метода RemoveAt. [3]
.RemoveAt(0); // удаление первого элемента
С помощью свойства Count у коллекций можно посмотреть количество
элементов. [3]
.2 Интерфейсы, используемые коллекциями
Классы коллекций в FCL в большинстве своем реализуют некоторый набор интерфейсов, представленный в таблице 1.2. [1]
Одной из отличительных особенностей FCL является то, что названия интерфейсов отражают описываемые ими абстракции. Точно так же названия классов отражают реализацию абстракций, определенных интерфейсами.
Например, абстракция «словарь» (по-другому ее еще называют map)
описывается интерфейсом IDictionary и реализуется классами Hashtable и
SortedList. Название класса Hashtable отражает, что в качестве основного
алгоритма реализации в нем используется алгоритм хэш-таблицы, а в SortedList -
сортированного массива. [1]
Таблица 1.2
Стандартные интерфейсы, реализуемые коллекциями в .NET
|
Название |
Описание |
|
IEnumerable |
Предоставляет итератор, который поддерживает простой перебор элементов коллекции. |
|
ICollection |
Определяет методы, позволяющие определить количество элементов в коллекции, а также методы синхронизации для коллекций. |
|
IList |
Представляет интерфейс коллекции объектов, каждый из которых может быть получен по индексу. Также определяет методы модификации коллекции. |
|
IDictionary |
Представляет интерфейс коллекции пар «ключ-значение». |
|
ICloneable |
Определяет метод, позволяющий создать копию объекта. |
Кроме непосредственно реализуемых коллекциями интерфейсов, перечисленных
в таблице 2, имеется также набор дополнительных интерфейсов, используемых
коллекциями или возвращаемых ими. Их список приведен в таблице 1.3. [1]
Таблица 1.3 Дополнительные интерфейсы, используемые коллекциями
|
Название |
Описание |
|
IComparer |
Определяет метод, осуществляющий сравнение двух объектов. |
|
IEnumerator |
Определяет методы, позволяющие осуществить простой перебор элементов коллекции. Возвращается методом GetEnumerator интерфейса IEnumerable. |
|
IComparable |
Используется при поиске и сортировке объектов. Может быть реализован типами, для которых определены операции сравнения. |
|
IDictionaryEnumerator |
Позволяет перебрать элементы словаря. |
|
IHashCodeProvider |
Определяет метод, позволяющий вычислить хэш-код для объекта. |
Интерфейс IEnumerable.
Все коллекции в FCL реализуют интерфейс IEnumerable. Этот интерфейс позволяет перебрать элементы коллекции в цикле. Интерфейс описывает всего один метод:
GetEnumerator();
Этот метод возвращает ссылку на интерфейс IEnumerator (перечислитель), при помощи которого можно осуществить перебор всех элементов коллекции. Для одного экземпляра коллекции можно одновременно запросить несколько перечислителей. Поэтому такого понятия, как «текущий элемент», нет. [1]
Интерфейс IEnumerator.
Этот интерфейс предназначен для перебора значений коллекции. В состав этого интерфейса входят: MoveNext(), Reset() и свойство Current.() позволяет сбросить состояние перечислителя в начальное состояние. В этом состоянии перечислитель находится сразу после его создания, при этом переход к следующему элементу приведет к тому, что текущим элементом станет первый элемент коллекции. [1]
Метод MoveNext() как раз и осуществляет переход к следующему элементу коллекции. Таким образом, MoveNext() нужно вызывать непосредственно перед обращением к первому или следующему элементу.
Свойство Current предоставляет доступ к текущему элементу. [1]
Ниже представлен пример использования этого интерфейса.
enumerator = ((IEnumerable)someCollection).GetEnumerator();(enumerator.MoveNext())
{elem = (ElemType)enumerator.Current();
// ... какие-то действия с элементом коллекции.
}
Любое изменение содержимого коллекции или количества ее элементов приводит к тому, что перечислитель становится недействительным. Так что если коллекция изменилась, попытка обратиться к методам или свойствам интерфейса IEnumerator должна вызвать исключение. Но эти интерфейсы - это всего лишь декларация намерений. Реализация интерфейсов целиком и полностью лежит на разработчиках конкретных классов. Так, все коллекции, входящие в пространство имен System.Collections, поддерживают это соглашение. Но IEnumerator реализуется также и встроенными массивами, которые этому правилу не удовлетворяют. [2]
Использовать связку IEnumerable/IEnumerator удобнее всего с помощью оператора foreach. Так, приведенный выше пример можно переписать следующим образом:
(ElemType elem in someCollection)
{
// ... какие-то действия с элементом коллекции.
}
Интерфейс ICollection
Интерфейс ICollection наследуется от IEnumerable:
interface ICollection: Ienumerable
Он определяет свойство, при помощи которого можно получить число элементов коллекции:
Count {get;}
Помимо этого свойства, интерфейс определяет метод:
CopyTo(Array array, int index);
Задачей этого метода является копирование элементов коллекции в массив. Копирование производится, начиная с элемента, индекс которого указан как второй аргумент метода. Ссылка на массив передается в качестве первого параметра. Размер массива должен быть достаточным для размещения копируемых элементов. [1]
Свойство SyncRoot возвращает ссылку на объект, который должен использоваться для синхронизации доступа к объекту. Необходимость в таком объекте возникает при создании сложных коллекций. Ниже представлен пример использования свойства SyncRoot:
(myCollection.SyncRoot)
{[0] = myCollection[1] + myCollection[2];
}
Для обеспечения корректной работы коллекции в многопоточной среде часто бывает удобно не делать синхронизацию вручную, а воспользоваться оберткой вокруг коллекции, обеспечивающей синхронизацию доступа к коллекции. Свойство IsSynchronized позволяет определить, нужна ли такая обертка имеющейся ссылке на коллекцию, или она уже и так потокобезопасна. [2]
Интерфейс IList.
Описанные выше методы и свойства позволяют просто «гонять» итераторы от одного элемента коллекции к другому, и узнавать количество элементов коллекции. Если не будут реализованы собственные методы доступа к данным коллекции, коллекцией пользоваться не удастся. Так вот, интерфейс IList предоставляет полиморфный механизм манипуляции данными коллекции:
interface IList : ICollection, Ienumerable
В интерфейсе IList впервые встречается способ получить или присвоить какое-то значение элементу коллекции. Это делается с помощью индексатора:
this[int index] { get; set; }
Аргументом в данном случае является индекс элемента. [1]
Чтобы добавить элемент в коллекцию, можно воспользоваться методом:
Add(object value);
Метод должен вернуть индекс добавленного элемента. [1]
Если же необходимо вставить элемент в конкретное место коллекции, то можно использовать метод:
Insert(int index, object value);
В качестве первого аргумента методу передается позиция, в которую должен быть помещен новый элемент. Все элементы коллекции, идущие за этой позицией, будут сдвинуты назад на одну позицию. [2]
Чтобы удалить элемент, имеющий конкретное значение, можно использовать метод:
Remove(object value);
Для удаления элемента по его индексу нужно воспользоваться методом:
RemoveAt(int index);
Очистить коллекцию можно при помощи метода:
Clear();
Если нужно просто узнать, присутствует ли в коллекции элемент с заданным значением, можно воспользоваться методом:
Contains(object value);
Если же возникает задача узнать индекс объекта в коллекции, можно использовать метод IndexOf():
IndexOf(object value);
Свойство IsReadOnly позволяет узнать, предназначена ли коллекция только для чтения, то есть можно ли изменять число элементов коллекции и значения элементов. Свойство IsFixedSize помогает узнать, можно ли изменять число элементов коллекции после ее создания. [1]
Этот интерфейс описывает методы, которые должны быть у реализаций
абстракции «словарь» (ассоциативной коллекции - хранящей пары ключ/значение).
Ниже в таблице 1.4 представлены свойства интерфейса IDictionary, в таблице 1.5
- методы интерфейса IDictionary. [1]
Таблица 1.4 - Свойства интерфейса IDictionary
|
Свойство |
Описание |
|
IsFixedSize |
Позволяет узнать, имеет ли данная реализация IDictionary фиксированный размер. |
|
IsReadOnly |
Позволяет узнать, можно ли модифицировать коллекцию. |
|
Keys |
Возвращает ссылку на коллекцию (ICollection), содержащую список ключей словаря. |
|
Values |
Возвращает ссылку на коллекцию (ICollection), содержащую список значений словаря. |