Выбрать главу
пары “ключ-значение”, причем и ключ, и значение от носятся к типу 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() Располагает элеме