- •Содержание
- •Введение
- •Коллекции в .Net
- •Виды коллекций
- •Типы коллекций
- •Интерфейсы, используемые коллекциями
- •Необобщенные коллекции
- •Обобщенные коллекции
- •Основные обобщенные коллекции
- •Параллельные коллекции
- •Специальные и наблюдаемые коллекции
- •Специальные коллекции
- •Наблюдаемые коллекции
- •Битовые коллекции
- •Класс BitArray
- •Структура BitVector32
- •Реализация интерфейса iComparable
- •Реализация интерфейса iComparer
- •Перечислители
- •Применение обычного перечислителя
- •Применение перечислителя типа iDictionaryEnumerator
- •Реализация интерфейсов iEnumerable и iEnumerator
- •Итераторы и оператор yield
- •Именованный итератор
- •Заключение
- •Список использованных источников
- •Приложение а (обязательное) Листинги и результаты работы программ
Интерфейсы, используемые коллекциями
Классы коллекций в 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. Этот интерфейс позволяет перебрать элементы коллекции в цикле. Интерфейс описывает всего один метод:
IEnumerator GetEnumerator(); |
Этот метод возвращает ссылку на интерфейс IEnumerator (перечислитель), при помощи которого можно осуществить перебор всех элементов коллекции. Для одного экземпляра коллекции можно одновременно запросить несколько перечислителей. Поэтому такого понятия, как «текущий элемент», нет. [1]
Интерфейс IEnumerator
Этот интерфейс предназначен для перебора значений коллекции. В состав этого интерфейса входят: MoveNext(), Reset() и свойство Current.
Reset() позволяет сбросить состояние перечислителя в начальное состояние. В этом состоянии перечислитель находится сразу после его создания, при этом переход к следующему элементу приведет к тому, что текущим элементом станет первый элемент коллекции. [1]
Метод MoveNext() как раз и осуществляет переход к следующему элементу коллекции. Таким образом, MoveNext() нужно вызывать непосредственно перед обращением к первому или следующему элементу.
Свойство Current предоставляет доступ к текущему элементу. [1]
Ниже представлен пример использования этого интерфейса.
IEnumerator enumerator = ((IEnumerable)someCollection).GetEnumerator(); while (enumerator.MoveNext()) { ElemType elem = (ElemType)enumerator.Current(); // ... какие-то действия с элементом коллекции. } |
Любое изменение содержимого коллекции или количества ее элементов приводит к тому, что перечислитель становится недействительным. Так что если коллекция изменилась, попытка обратиться к методам или свойствам интерфейса IEnumerator должна вызвать исключение. Но эти интерфейсы – это всего лишь декларация намерений. Реализация интерфейсов целиком и полностью лежит на разработчиках конкретных классов. Так, все коллекции, входящие в пространство имен System.Collections, поддерживают это соглашение. Но IEnumerator реализуется также и встроенными массивами, которые этому правилу не удовлетворяют. [2]
Использовать связку IEnumerable/IEnumerator удобнее всего с помощью оператора foreach. Так, приведенный выше пример можно переписать следующим образом:
foreach (ElemType elem in someCollection) { // ... какие-то действия с элементом коллекции. } |
Интерфейс ICollection
Интерфейс ICollection наследуется от IEnumerable:
public interface ICollection: Ienumerable |
Он определяет свойство, при помощи которого можно получить число элементов коллекции:
int Count {get;} |
Помимо этого свойства, интерфейс определяет метод:
void CopyTo(Array array, int index); |
Задачей этого метода является копирование элементов коллекции в массив. Копирование производится, начиная с элемента, индекс которого указан как второй аргумент метода. Ссылка на массив передается в качестве первого параметра. Размер массива должен быть достаточным для размещения копируемых элементов. [1]
Свойство SyncRoot возвращает ссылку на объект, который должен использоваться для синхронизации доступа к объекту. Необходимость в таком объекте возникает при создании сложных коллекций. Ниже представлен пример использования свойства SyncRoot:
lock (myCollection.SyncRoot) { myCollection[0] = myCollection[1] + myCollection[2]; } |
Для обеспечения корректной работы коллекции в многопоточной среде часто бывает удобно не делать синхронизацию вручную, а воспользоваться оберткой вокруг коллекции, обеспечивающей синхронизацию доступа к коллекции. Свойство IsSynchronized позволяет определить, нужна ли такая обертка имеющейся ссылке на коллекцию, или она уже и так потокобезопасна. [2]
Интерфейс IList
Описанные выше методы и свойства позволяют просто «гонять» итераторы от одного элемента коллекции к другому, и узнавать количество элементов коллекции. Если не будут реализованы собственные методы доступа к данным коллекции, коллекцией пользоваться не удастся. Так вот, интерфейс IList предоставляет полиморфный механизм манипуляции данными коллекции:
public interface IList : ICollection, Ienumerable |
В интерфейсе IList впервые встречается способ получить или присвоить какое-то значение элементу коллекции. Это делается с помощью индексатора:
object this[int index] { get; set; } |
Аргументом в данном случае является индекс элемента. [1]
Чтобы добавить элемент в коллекцию, можно воспользоваться методом:
int Add(object value); |
Метод должен вернуть индекс добавленного элемента. [1]
Если же необходимо вставить элемент в конкретное место коллекции, то можно использовать метод:
void Insert(int index, object value); |
В качестве первого аргумента методу передается позиция, в которую должен быть помещен новый элемент. Все элементы коллекции, идущие за этой позицией, будут сдвинуты назад на одну позицию. [2]
Чтобы удалить элемент, имеющий конкретное значение, можно использовать метод:
void Remove(object value); |
Для удаления элемента по его индексу нужно воспользоваться методом:
void RemoveAt(int index); |
Очистить коллекцию можно при помощи метода:
void Clear(); |
Если нужно просто узнать, присутствует ли в коллекции элемент с заданным значением, можно воспользоваться методом:
bool Contains(object value); |
Если же возникает задача узнать индекс объекта в коллекции, можно использовать метод IndexOf():
int IndexOf(object value); |
Свойство IsReadOnly позволяет узнать, предназначена ли коллекция только для чтения, то есть можно ли изменять число элементов коллекции и значения элементов. Свойство IsFixedSize помогает узнать, можно ли изменять число элементов коллекции после ее создания. [1]
IDictionary
Этот интерфейс описывает методы, которые должны быть у реализаций абстракции «словарь» (ассоциативной коллекции – хранящей пары ключ/значение). Ниже в таблице 1.4 представлены свойства интерфейса IDictionary, в таблице 1.5 – методы интерфейса IDictionary. [1]
Таблица 1.4 – Свойства интерфейса IDictionary
Свойство |
Описание |
IsFixedSize |
Позволяет узнать, имеет ли данная реализация IDictionary фиксированный размер. |
IsReadOnly |
Позволяет узнать, можно ли модифицировать коллекцию. |
Keys |
Возвращает ссылку на коллекцию (ICollection), содержащую список ключей словаря. |
Values |
Возвращает ссылку на коллекцию (ICollection), содержащую список значений словаря. |
Таблица 1.5 – Методы интерфейса IDictionary
Метод |
Описание |
Add |
Позволяет добавить пару ключ/значение к словарю. |
Clear |
Очищает содержимое коллекции. |
Contains |
Позволяет определить, содержит ли коллекция элемент с заданным ключом. |
Продолжение таблицы 1.5
GetEnumerator |
Возвращает ссылку на перечислитель словаря – интерфейс IDictionaryEnumerator. |
Remove |
Позволяет удалить элемент с заданным ключом. |
Хотя интерфейс IDictionary объявляется производным от Enumerable и переход к следующему элементу может осуществляться методом MoveNext, обычно такая возможность не используется — коллекции, реализующие IDictionary, ориентируются в первую очередь на обращение по ключу, а не на последовательный перебор элементов. По этой причине интерфейс IDictionary зависит от интерфейса IDictionaryEnumerator, который расширяет Enumerator и дополняет его тремя новыми свойствами:
Entry: возвращает пару «ключ/значение» для текущего элемента словаря.
Key: возвращает текущий ключ.
Value: возвращает ссылку на текущее значение. [3]
