пары “ключ-значение”, причем и ключ, и значение от
носятся к типу string
OrderedDictionary Предназначен для коллекций, в которых хранятся индексируе
мые пары “ключ-значение”
StringCollection Предназначен для коллекций, оптимизированных для хранения
символьных строк
StringDictionary Предназначен для хеш-таблиц, в которых хранятся пары
“ключ-значение”, причем и ключ, и значение относятся к типу
string
Кроме того, в пространстве имен System.Collections определены три базовых
абстрактных класса: CollectionBase, ReadOnlyCollectionBase и DictionaryBase.
Эти классы могут наследоваться и служить в качестве отправной точки для разработки
собственных специальных коллекций.
Обобщенные коллекции
Благодаря внедрению обобщений прикладной интерфейс Collections API значи
тельно расширился, в результате чего количество классов коллекций и интерфей
сов удвоилось. Обобщенные коллекции объявляются в пространстве имен System.
Collections.Generic. Как правило, классы обобщенных коллекций являются не бо
лее чем обобщенными эквивалентами рассматривавшихся ранее классов необобщен
ных коллекций, хотя это соответствие не является взаимно однозначным. Например,
в классе обобщенной коллекции LinkedList реализуется двунаправленный список,
тогда как в необобщенном эквиваленте его не существует. В некоторых случаях одни
и те же функции существуют параллельно в классах обобщенных и необобщенных кол
лекций, хотя и под разными именами. Так, обобщенный вариант класса ArrayList
называется List, а обобщенный вариант класса HashTable — Dictionary. Кроме
того, конкретное содержимое различных интерфейсов и классов реорганизуется с ми
нимальными изменениями для переноса некоторых функций из одного интерфейса в
другой. Но в целом, имея ясное представление о необобщенных коллекциях, можно
без особого труда научиться применять и обобщенные коллекции.
Как правило, обобщенные коллекции действуют по тому же принципу, что и не
обобщенные, за исключением того, что обобщенные коллекции типизированы. Это
означает, что в обобщенной коллекции можно хранить только те элементы, которые
совместимы по типу с ее аргументом. Так, если требуется коллекция для хранения не
связанных друг с другом разнотипных данных, то для этой цели следует использовать
классы необобщенных коллекций. А во всех остальных случаях, когда в коллекции
должны храниться объекты только одного типа, выбор рекомендуется останавливать
на классах обобщенных коллекций.
Обобщенные коллекции определяются в ряде интерфейсов и классов, реализую
щих эти интерфейсы. Все они описываются далее по порядку.
Интерфейсы обобщенных коллекций
В пространстве имен System.Collections.Generic определен целый ряд интер
фейсов обобщенных коллекций, имеющих соответствующие аналоги среди интерфей
сов необобщенных коллекций. Все эти интерфейсы сведены в табл. 25.10.
Таблица 25.10. Интерфейсы обобщенных коллекций
Интерфейс Описание
ICollection Определяет основополагающие свойства обобщенных
коллекций
IComparer Определяет обобщенный метод Compare() для срав
нения объектов, хранящихся в коллекции
IDictionary Определяет обобщенную коллекцию, состоящую из пар
"ключ-значение’’
Окончание табл. 25.10
Интерфейс Описание
IEnumerable Определяет обобщенный метод GetEnumerator(),
предоставляющий перечислитель для любого класса
коллекции
Enumerator Предоставляет методы, позволяющие получать содержи
мое коллекции по очереди
IEqualityComparer Сравнивает два объекта на предмет равенства
IList Определяет обобщенную коллекцию, доступ к которой
можно получить с помощью индексатора
Интерфейс ICollection
В интерфейсе ICollection определен ряд свойств, которые являются общими
для всех обобщенных коллекций. Интерфейс ICollection является обобщенным
вариантом необобщенного интерфейса ICollection, хотя между ними имеются не
которые отличия.
Итак, в интерфейсе ICollection определены следующие свойства.
int Count { get; }
bool IsReadOnly { get; }
Свойство Count содержит ряд элементов, хранящихся в данный момент в коллек
ции. А свойство IsReadOnly имеет логическое значение true, если коллекция доступ
на только для чтения. Если же коллекция доступна как для чтения, так и для записи, то
данное свойство имеет логическое значение false.
Кроме того, в интерфейсе ICollection определены перечисленные ниже ме
тоды. Обратите внимание на то, что в этом обобщенном интерфейсе определено не
сколько большее количество методов, чем в его необобщенном аналоге.
Некоторые из перечисленных выше методов генерируют исключе
ние NotSupportedException, если коллекция доступна только для чтения.
Метод Описание
void Add(T item) Добавляет элемент item в вызывающую коллекцию. Гене
рирует исключение NotSupportedException, если кол
лекция доступна только для чтения
void Clear() Удаляет все элементы из вызывающей коллекции
bool Contains(T item) Возвращает логическое значение true, если вызывающая
коллекция содержит элемент item, а иначе — логическое
значение false
void CopyTo(T[] array,
int arrayIndex)
Копирует содержимое вызывающей коллекции в массив
array, начиная с элемента, указываемого по индексу
arrayIndex
void Remove(T item) Удаляет первое вхождение элемента item в вызывающей
коллекции. Возвращает логическое значение true, если
элемент item удален. А если этот элемент не найден в вы
зывающей коллекции, то возвращается логическое значе
ние false
А поскольку интерфейс ICollection наследует от интерфейсов IEnumerable и
IEnumerable, то он включает в себя также обобщенную и необобщенную формы
метода GetEnumerator().
Благодаря тому что в интерфейсе ICollection реализуется интерфейс
IEnumerable, в нем поддерживаются также методы расширения, определенные в
классе Enumerable. Несмотря на то что методы расширения предназначены главным
образом для поддержки LINQ, им можно найти и другое применение, в том числе и
в коллекциях.
Интерфейс IList
В интерфейсе IList определяется такое поведение обобщенной коллекции,
которое позволяет осуществлять доступ к ее элементам по индексу с отсчетом от
нуля. Этот интерфейс наследует от интерфейсов IEnumerable, IEnumerable и
ICollection и поэтому является обобщенным вариантом необобщенного интер
фейса IList. Методы, определенные в интерфейсе IList, перечислены в табл.
25.11. В двух из этих методов предусматривается модификация коллекции. Если же
коллекция доступна только для чтения или имеет фиксированный размер, то методы
Insert() и RemoveAt() генерируют исключение NotSupportedException.
Таблица 25.11. Методы, определенные в интерфейсе IList
Метод Описание
int IndexOf(Т item) Возвращает индекс первого вхождения элемента item в
вызывающей коллекции. Если элемент item не обнару
жен, то метод возвращает значение -1
void Insert(int index,
T item)
Вставляет в вызывающую коллекцию элемент item по
индексу index
void RemoveAtfint index) Удаляет из вызывающей коллекции элемент, расположен
ный по указанному индексу index
Кроме того, в интерфейсе IList определяется индексатор
Т this[int index] { get; set; }
который устанавливает или возвращает значение элемента коллекции по указанному
индексу index.
Интерфейс IDictionary
В интерфейсе IDictionary определяется такое поведение обоб
щенной коллекции, которое позволяет преобразовать уникальные ключи в соответ
ствующие значения. Это означает, что в данном интерфейсе определяется коллекция, в
которой хранятся пары "ключ-значение". Интерфейс IDictionary
наследует от интерфейсов IEnumerable, IEnumerable> и ICollection> и поэтому является
обобщенным вариантом необобщенного интерфейса IDictionary. Методы, объяв
ленные в интерфейсе IDictionary, приведены в табл. 25.12. Все эти
методы генерируют исключение ArgumentNullException при попытке указать пу
стой ключ.
Кроме того, в интерфейсе IDictionary определены перечислен
ные ниже свойства.
Следует иметь в виду, что ключи и значения, содержащиеся в коллекции, доступны
отдельными списками с помощью свойств Keys и Values.
И наконец, в интерфейсе IDictionary определяется следующий
индексатор.
TValue this[TKey key] { get; set; }
Этот индексатор служит для получения и установки значения элемента коллекции,
а также для добавления в коллекцию нового элемента. Следует, однако, иметь в виду,
что в качестве индекса в данном случае служит ключ элемента, а не сам индекс.
Интерфейсы IEnumerable и IEnumerator
Интерфейсы IEnumerable и IEnumerator являются обобщенными эк
вивалентами рассмотренных ранее необобщенных интерфейсов IEnumerable и
IEnumerator. В них объявляются аналогичные методы и свойства, да и действуют они
по тому же принципу. Разумеется, обобщенные интерфейсы оперируют данными
только того типа, который указывается в аргументе типа.
В интерфейсе IEnumerable метод GetEnumerator() объявляется следующим
образом.
IEnumerator GetEnumerator()
Этот метод возвращает перечислитель типа Т для коллекции. А это означает, что
он возвращает типизированный перечислитель.
Таблица 25.12. Методы, определенные в интерфейсе IDictionary
Метод Описание
void Add(TKey key, TValue
value)
Добавляет в вызывающую коллекцию пару “ключ-
значение”, определяемую параметрами key и value.
Генерирует исключение ArgumentException, если
ключ key уже находится в коллекции
bool Contains(TKey key) Возвращает логическое значение true, если вызы
вающая коллекция содержит элемент key в качестве
ключа, а иначе — логическое значение false
bool Remove(TKey key) Удаляет из коллекции элемент, ключ которого равен
значению key
bool TryGetValue(TKey key,
out TValue value)
Предпринимает попытку извлечь значение из коллек
ции по указанному ключу key и присвоить это значе
ние переменной value. При удачном исходе опера
ции возвращается логическое значение true, а ина
че — логическое значение false. Если ключ key не
найден, переменной value присваивается значение,
выбираемое по умолчанию
Свойство Описание
ICollection Keys { get; } Получает коллекцию ключей
ICollection Values { get; } Получает коллекцию значений
Кроме того, в интерфейсе IEnumerable определяются два таких же метода, как
и в необобщенном его варианте: MoveNext() и Reset(). В этом интерфейсе объявля
ется также обобщенный вариант свойства Current.
Т Current { get; }
Это свойство возвращает ссылку типа Т на следующий объект. А это означает, что
обобщенный вариант свойства Current является типизированным.
Но между интерфейсами IEnumerator и IEnumerator имеется одно важное
различие: интерфейс IEnumerator наследует от интерфейса IDisposable, тогда
как интерфейс IEnumerator не наследует от него. В интерфейсе IDisposable опреде
ляется метод Dispose(), который служит для освобождения неуправляемых ресурсов.
ПРИМЕЧАНИЕ
В интерфейсе IEnumerable реализуется также необобщенный интерфейс
IEnumerable. Это означает, что в нем поддерживается необобщенный вариант метода
GetEnumerator(). Кроме того, в интерфейсе IEnumerable реализуется необобщен
ный интерфейс IEnumerator, а следовательно, в нем поддерживаются необобщенные ва
рианты свойства Current.
Интерфейс IComparer
Интерфейс IComparer является обобщенным вариантом рассмотренного ранее
интерфейса IComparer. Главное отличие между ними заключается в том, что интер
фейс IComparer обеспечивает типовую безопасность. В нем обобщенный вариант
метода Compare() объявляется следующим образом.
int Compare(Т х, Т у)
В этом методе сравниваются объекты х и у. Он возвращает положительное значе
ние, если значение объекта х больше, чем у объекта у; отрицательное — если значение
объекта х меньше, чем у объекта у; и нулевое значение — если сравниваемые значения
равны.
Интерфейс IEqualityComparer
Интерфейс IEqualityComparer полностью соответствует своему необобщен
ному аналогу EqualityComparer. В нем определяются два следующих метода.
bool Equals (Т х, Т у)
int GetHashCode(Т obj)
Метод Equals() должен возвратить логическое значение true, если значения
объектов х и у равны. А метод GetHashCode() возвращает хеш-код для объекта obj.
Если два сравниваемых объекта равны, то их хеш-коды также должны быть одинаковы.
Интерфейс ISet
Интерфейс ISet был добавлен в версию 4.0 среды .NET Framework. Он опре
деляет поведение обобщенной коллекции, реализующей ряд уникальных элементов.
Этот интерфейс наследует от интерфейсов IEnumerable, IEnumerable, а также
ICollection. В интерфейсе ISet определен ряд методов, перечисленных
в табл. 25.13. Обратите внимание на то, что параметры этих методов указываются как
относящиеся к типу IEnumerable. Это означает, что в качестве второго аргумен
та методу можно передать нечто, отличающееся от объектов типа ISet Но чаще
всего оба аргумента оказываются экземплярами объектов типа ISet
Таблица 25.13. Методы, определенные в интерфейсе ISet
Метод Описание
void ExceptWith(Ienumerable
other)
Удаляет из вызывающего множества те элементы,
которые содержатся в другом множестве other
void
IntersectWith(IEnumerable
other)
После вызова этого метода вызывающее множе
ство содержит пересечение своих элементов с эле
ментами другого множества other
bool
IsProperSubsetOf(IEnumerable
other)
Возвращает логическое значение true, если вы
зывающее множество является правильным под
множеством другого множества other, а иначе —
логическое значение false
bool IsProperSupersetOf(IEnumera
ble other)
возвращает логическое значение true, если вы
зывающее множество является правильным над
множеством другого множества other, а иначе —
логическое значение false
bool IsSubsetOf(IEnumerable
other)
Возвращает логическое значение true, если вы
зывающее множество является подмножеством
другого множества other, а иначе — логическое
значение false
bool
IsSupersetOf(IEnumerable
other)
Возвращает логическое значение true, если вы
зывающее множество является надмножеством
другого множества other, а иначе — логическое
значение false
bool Overlaps(IEnumerable
other)
Возвращает логическое значение true, если вы
зывающее множество и другое множество other
содержат хотя бы один общий элемент, а иначе —
логическое значение false
bool SetEquals(IEnumerable
other)
Возвращает логическое значение true, если все
элементы вызывающего множества и другого мно
жества other оказываются общими, а иначе — ло
гическое значение false. Порядок расположения
элементов не имеет значения, а дублирующиеся
элементы во другом множестве other игнориру
ются
void SymmetricExceptWith
(IEnumerable other)
После вызова этого метода вызывающее множе
ство будет содержать симметрическую разность
своих элементов и элементов другого множества
other
void UnionWith(IEnumerable
other)
После вызова этого метода вызывающее множе
ство будет содержать объединение своих элемен
тов и элементов другого множества other
Структура KeyValuePair
В пространстве имен System.Collections.Generic определена структура
KeyValuePair. Она служит для хранения ключа и его значения
и применяется в классах обобщенных коллекций, в которых хранятся пары "ключ-
значение", как, например, в классе Dictionary. В этой структуре
определяются два следующих свойства.
public TKey Key { get; };
public TValue Value { get; };
В этих свойствах хранятся ключ и значение соответствующего элемента коллекции.
Для построения объекта типа KeyValuePair служит конструктор:
public KeyValuePair(TKey key, TValue value)
где key обозначает ключ, a value — значение.
Классы обобщенных коллекций
Как упоминалось ранее, классы обобщенных коллекций по большей части соот
ветствуют своим необобщенным аналогам, хотя в некоторых случаях они носят другие
имена. Отличаются они также своей организацией и функциональными возможно
стями. Классы обобщенных коллекций определяются в пространстве имен System.
Collections.Generic. В табл. 25.14 приведены классы, рассматриваемые в этой гла
ве. Эти классы составляют основу обобщенных коллекций.
Таблица 25.14. Основные классы обобщенных коллекций
Класс Описание
Dictionary Сохраняет пары “ключ-значение". Обеспечивает такие
же функциональные возможности, как и необобщенный
класс Hashtable
HashSet Сохраняет ряд уникальных значений, используя хеш-
таблицу
LinkedList Сохраняет элементы в двунаправленном списке
List Создает динамический массив. Обеспечивает такие же
функциональные возможности, как и необобщенный
класс ArrayList
Queue Создает очередь. Обеспечивает такие же функциональ
ные возможности, как и необобщенный класс Queue
SortedDictionary
Создает отсортированный список из пар “ключ-
значение”
SortedList Создает отсортированный список из пар "ключ-
значение”. Обеспечивает такие же функциональные воз
можности, как и необобщенный класс SortedList
SortedSet Создает отсортированное множество
Stack Создает стек. Обеспечивает такие же функциональные
возможности, как и необобщенный класс Stack
ПРИМЕЧАНИЕ
В пространстве имен System.Collections.Generic находятся также следующие
классы: класс SynchronizedCollection синхронизированной коллекции на осно
ве класса IList; класс SynchronizedReadOnlyCollection, доступной толь
ко для чтения синхронизированной коллекции на основе класса lList; абстрактный
класс SynchronizedKeyCollection, служащий в качестве базового для клас
са коллекции System.ServiceModel.UriSchemeKeyedCollection; а также класс
KeyedByTypeCollection коллекции, в которой в качестве ключей используются от
дельные типы данных.
Класс List
В классе List реализуется обобщенный динамический массив. Он ничем
принципиально не отличается от класса необобщенной коллекции ArrayList.
В этом классе реализуются интерфейсы ICollection, ICollection, IList,
IList, IEnumerable и IEnumerable. У класса List имеются следующие
конструкторы.
public List()
public List(IEnumerable collection)
public List(int capacity)
Первый конструктор создает пустую коллекцию класса List с выбираемой по
умолчанию первоначальной емкостью. Второй конструктор создает коллекцию типа
List с количеством инициализируемых элементов, которое определяется параметром
collection и равно первоначальной емкости массива. Третий конструктор создает
коллекцию типа List, имеющую первоначальную емкость, задаваемую параметром
capacity. В данном случае емкость обозначает размер базового массива, используе
мого для хранения элементов коллекции. Емкость коллекции, создаваемой в виде ди
намического массива, может увеличиваться автоматически по мере добавления в нее
элементов.
В классе List определяется ряд собственных методов, помимо тех, что уже объ
явлены в интерфейсах, которые в нем реализуются. Некоторые из наиболее часто ис
пользуемых методов этого класса перечислены в табл. 25.15.
Таблица 25.15. Наиболее часто используемые методы, определенные в классе List
Метод Описание
public virtual void
AddRange(Icollection
collection)
Добавляет элементы из коллекции collection в
конец вызывающей коллекции типа ArrayList
public virtual int
BinarySearch(T item)
Выполняет поиск в вызывающей коллекции значе
ния, задаваемого параметром item. Возвращает
индекс совпавшего элемента. Если искомое зна
чение не найдено, возвращается отрицательное
значение. Вызывающий список должен быть отсо
ртирован
Продолжение табл. 25.15
Метод Описание
public int BinarySearch(Т
item, IComparer comparer)
Выполняет поиск в вызывающей коллекции значе
ния, задаваемого параметром item, используя для
сравнения указанный способ, определяемый пара
метром comparer. Возвращает индекс совпавшего
элемента. Если искомое значение не найдено, воз
вращается отрицательное значение. Вызывающий
список должен быть отсортирован
public int BinarySearch(int
index, int count, T item,
IComparer comparer)
Выполняет поиск в вызывающей коллекции значе
ния, задаваемого параметром item, используя для
сравнения указанный способ, определяемый пара
метром comparer. Поиск начинается с элемента,
указываемого по индексу index, и включает ко
личество элементов, определяемых параметром
count. Метод возвращает индекс совпавшего
элемента. Если искомое значение не найдено, воз
вращается отрицательное значение. Вызывающий
список должен быть отсортирован
public List GetRange(int
index, int count)
Возвращает часть вызывающей коллекции. Часть
возвращаемой коллекции начинается с элемента,
указываемого по индексу index, и включает коли
чество элементов, задаваемое параметром count.
Возвращаемый объект ссылается на те же элемен
ты, что и вызывающий объект
public int IndexOf(T item) Возвращает индекс первого вхождения элемента
item в вызывающей коллекции. Если искомый эле
мент не обнаружен, возвращается значение -1
public void InsertRange(int
index, IEnumerable
collection)
Вставляет элементы коллекции collection в вы
зывающую коллекцию, начиная с элемента, указы
ваемого по индексу index
public int LastlndexOf(T
item)
Возвращает индекс последнего вхождения элемен
та item в вызывающей коллекции. Если искомый
элемент не обнаружен, возвращается значение -1
public void RemoveRange(int
index, int count)
Удаляет часть вызывающей коллекции, начиная с
элемента, указываемого по индексу index, и вклю
чая количество элементов, определяемое параме
тром count
public void Reverse() Располагает элеме