Полное руководство. С# 4.0 - Шилдт Герберт
ГЛАВА 25. Коллекции, перечислители и итераторы
В этой главе речь пойдет об одной из самых важныхсоставляющих среды .NET Framework: коллекциях. В С# коллекция представляет собой совокупностьобъектов. В среде .NET Framework имеется немало интерфейсов и классов, в которых определяются и реализуютсяразличные типы коллекций. Коллекции упрощают решение многих задач программирования благодаря тому, чтопредлагают готовые решения для создания целого рядатипичных, но порой трудоемких для разработки структурданных. Например, в среду .NET Framework встроены коллекции, предназначенные для поддержки динамическихмассивов, связных списков, стеков, очередей и хеш-таблиц.Коллекции являются современным технологическим средством, заслуживающим пристального внимания всех, ктопрограммирует на С#.Первоначально существовали только классы необобщенных коллекций. Но с внедрением обобщений в версииC# 2.0 среда .NET Framework была дополнена многиминовыми обобщенными классами и интерфейсами. Благодаря введению обобщенных коллекций общее количествоклассов и интерфейсов удвоилось. Вместе с библиотекойраспараллеливания задач (TPL) в версии 4.0 среды .NETFramework появился ряд новых классов коллекций, предназначенных для применения в тех случаях, когда доступ кколлекции осуществляется из нескольких потоков. Нетрудно догадаться, что прикладной интерфейс Collections APIсоставляет значительную часть среды .NET Framework.Кроме того, в настоящей главе рассматриваются два средства, непосредственно связанные с коллекциями: перечислители и итераторы. И те и другие позволяют поочередно обращаться к содержимому класса коллекции в цикле foreach.Краткий обзор коллекций
Главное преимущество коллекций заключается в том, что они стандартизируют обработку групп объектов в программе. Все коллекции разработаны на основе наборачетко определенных интерфейсов. Некоторые встроенные реализации таких интерфейсов, в том числе ArrayList, Hashtable, Stack и Queue, могут применяться в исходном виде и без каких-либо изменений. Имеется также возможность реализоватьсобственную коллекцию, хотя потребность в этом возникает крайне редко.В среде .NET Framework поддерживаются пять типов коллекций: необобщенные,специальные, с поразрядной организацией, обобщенные и параллельные. Необобщенные коллекции реализуют ряд основных структур данных, включая динамический массив, стек, очередь, а также словари, в которых можно хранить пары "ключ-значение".В отношении необобщенных коллекций важно иметь в виду следующее: они оперируют данными типа object.Таким образом, необобщенные коллекции могут служить для хранения данныхлюбого типа, причем в одной коллекции допускается наличие разнотипных данных.Очевидно, что такие коллекции не типизированы, поскольку в них хранятся ссылкина данные типа object. Классы и интерфейсы необобщенных коллекций находятся впространстве имен System.Collections.Специальные коллекции оперируют данными конкретного типа или же делаютэто каким-то особым образом. Например, имеются специальные коллекции для символьных строк, а также специальные коллекции, в которых используется однонаправленный список. Специальные коллекции объявляются в пространстве имен System.Collections.Specialized.В прикладном интерфейсе Collections API определена одна коллекция с поразрядной организацией — это BitArray. Коллекция типа BitArray поддерживает поразрядные операции, т.е. операции над отдельными двоичными разрядами, напримерИ иди исключающее ИЛИ, а следовательно, она существенно отличается своими возможностями от остальных типов коллекций. Коллекция типа BitArray объявляетсяв пространстве имен System.Collections.Обобщенные коллекции обеспечивают обобщенную реализацию нескольких стандартных структур данных, включая связные списки, стеки, очереди и словари. Такиеколлекции являются типизированными в силу их обобщенного характера. Это означает, что в обобщенной коллекции могут храниться только такие элементы данных,которые совместимы по типу с данной коллекцией. Благодаря этому исключаетсяслучайное несовпадение типов. Обобщенные коллекции объявляются в пространствеимен System.Collections.Generic.Параллельные коллекции поддерживают многопоточный доступ к коллекции. Этообобщенные коллекции, определенные в пространстве имен System.Collections.Concurrent.В пространстве имен System.Collections.ObjectModel находится также рядклассов, поддерживающих создание пользователями собственных обобщенных коллекций.Основополагающим для всех коллекций является понятие перечислителя, которыйподдерживается в необобщенных интерфейсах IEnumerator и IEnumerable, а такжев обобщенных интерфейсах IEnumerator и IEnumerable. Перечислитель обеспечивает стандартный способ поочередного доступа к элементам коллекции. Следовательно, он перечисляет содержимое коллекции. В каждой коллекции должна бытьреализована обобщенная или необобщенная форма интерфейса IEnumerable, поэтому элементы любого класса коллекции должны быть доступны посредством методов,определенных в интерфейсе IEnumerator или IEnumerator. Это означает, что,внеся минимальные изменения в код циклического обращения к коллекции одноготипа, его можно использовать для аналогичного обращения к коллекции другого типа.Любопытно, что для поочередного обращения к содержимому коллекции в циклеforeach используется перечислитель.Основополагающим для всех коллекций является понятие перечислителя, которыйподдерживается в необобщенных интерфейсах IEnumerator и IEnumerable, а такжев обобщенных интерфейсах IEnumerator и IEnumerable. Перечислитель обеспечивает стандартный способ поочередного доступа к элементам коллекции. Следовательно, он перечисляет содержимое коллекции. В каждой коллекции должна бытьреализована обобщенная или необобщенная форма интерфейса IEnumerable, поэтому элементы любого класса коллекции должны быть доступны посредством методов,определенных в интерфейсе IEnumerator или IEnumerator. Это означает, что,внеся минимальные изменения в код циклического обращения к коллекции одноготипа, его можно использовать для аналогичного обращения к коллекции другого типа.Любопытно, что для поочередного обращения к содержимому коллекции в циклеforeach используется перечислитель.С перечислителем непосредственно связано другое средство, называемое итератором. Это средство упрощает процесс создания классов коллекций, например специальных, поочередное обращение к которым организуется в цикле foreach. Итераторытакже рассматриваются в этой главе.И последнее замечание: если у вас имеется некоторый опыт программированияна C++, то вам, вероятно, будет полезно знать, что классы коллекций по своей сути подобны классам стандартной библиотеки шаблонов (Standard Template Library — STL),определенной в C++. То, что в программировании на C++ называется контейнером,в программировании на C# называется коллекцией. Это же относится и к Java. Есливы знакомы с библиотекой Collections Framework для Java, то научиться пользоватьсяколлекциями в C# не составит для вас большого труда.В силу характерных отличий каждый из пяти типов коллекций (необобщенных,обобщенных, специальных, с поразрядной организацией и параллельных) будет рассмотрен далее в этой главе отдельно.Необобщенные коллекцииНеобобщенные коллекции вошли в состав среды .NET Framework еще в версии 1.0.Они определяются в пространстве имен System.Collections. Необобщенные коллекции представляют собой структуры данных общего назначения, оперирующие ссылками на объекты. Таким образом, они позволяют манипулировать объектом любого типа,хотя и не типизированным способом. В этом состоит их преимущество и в то же время недостаток. Благодаря тому что необобщенные коллекции оперируют ссылками наобъекты, в них можно хранить разнотипные данные. Это удобно в тех случаях, когда требуется манипулировать совокупностью разнотипных объектов или же когда типы хранящихся в коллекции объектов заранее неизвестны. Но если коллекция предназначаетсядля хранения объекта конкретного типа, то необобщенные коллекции не обеспечиваюттиповую безопасность, которую можно обнаружить в обобщенных коллекциях.Необобщенные коллекции определены в ряде интерфейсов и классов, реализующих эти интерфейсы. Все они рассматриваются далее по порядку.Интерфейсы необобщенных коллекцийВ пространстве имен System.Collections определен целый ряд интерфейсовнеобобщенных коллекций. Начинать рассмотрение необобщенных коллекций следует именно с интерфейсов, поскольку они определяют функциональные возможности,которые являются общими для всех классов необобщенных коллекций. Интерфейсы,служащие опорой для необобщенных коллекций, сведены в табл. 25.1. Каждый из этихинтерфейсов подробно описывается далее.Таблица 25.1. Интерфейсы необобщенных коллекцийИнтерфейс ICollectionИнтерфейс ICollection служит основанием, на котором построены все необобщенные коллекции. В нем объявляются основные методы и свойства для всех необобщенных коллекций. Он также наследует от интерфейса IEnumerable.В интерфейсе ICollection определяются перечисленные ниже свойства.Свойство Count используется чаще всего, поскольку оно содержит количество элементов, хранящихся в коллекции на данный момент. Если значение свойства Countравно нулю, то коллекция считается пустой.В интерфейсе ICollection определяется следующий метод.void СоруТо(Array target, int startIdx)Интерфейс ОписаниеICollection Определяет элементы, которые должны иметь все необобщенные коллекцииIComparer Определяет метод Compare() для сравнения объектов, хранящихся в коллекцииIDictionary Определяет коллекцию, состоящую из пар "ключ-значение"IDictionaryEnumerator Определяет перечислитель для коллекции, реализующей интерфейс IDictionaryIEnumerable Определяет метод GetEnumerator(), предоставляющийперечислитель для любого класса коллекцииIEnumerator Предоставляет методы, позволяющие получать содержимоеколлекции по очередиIEqualityComparer Сравнивает два объекта на предмет равенстваIHashCodeProvider Считается устаревшим. Вместо него следует использовать интерфейс IEqualityComparerIList Определяет коллекцию, доступ к которой можно получить с помощью индексатораIStructuralComparable Определяет метод CompareTo(), применяемый для структурного сравненияIStructuralEquatable Определяет метод Equals(), применяемый для выясненияструктурного, а не ссылочного равенства. Кроме того, определяет метод GetHashCode()Метод СоруТо() копирует содержимое коллекции в массив target, начиная с элемента, указываемого по индексу startIdx. Следовательно, метод СоруТо() обеспечивает в C# переход от коллекции к стандартному массиву.Благодаря тому что интерфейс ICollection наследует от интерфейса IEnumerable,в его состав входит также единственный метод, определенный в интерфейсеIEnumerable. Это метод GetEnumerator(), объявляемый следующим образом.IEnumerator GetEnumerator()Он возвращает перечислитель для коллекции.Вследствие того же наследования от интерфейса IEnumerable в интерфейсе ICollection определяются также четыре следующих метода расширения:AsParallel(), AsQueryable(), Cast() и OfType(). В частности, метод AsParallel()объявляется в классе System.Linq.ParallelEnumerable, метод AsQueryable() —в классе System.Linq.Queryable, а методы Cast() и OfType() — в классе System.Linq.Enumerable. Эти методы предназначены главным образом для поддержки LINQ,хотя их можно применять и в других целях.Интерфейс IListВ интерфейсе IList объявляется такое поведение необобщенной коллекции, которое позволяет осуществлять доступ к ее элементам по индексу с отсчетом от нуля.Этот интерфейс наследует от интерфейсов ICollection и IEnumerable. Помимометодов, определенных в этих интерфейсах, в интерфейсе IList определяется рядсобственных методов. Все эти методы сведены в табл. 25.2. В некоторых из них предусматривается модификация коллекции. Если же коллекция доступна только для чтения или имеет фиксированный размер, то в этих методах генерируется исключениеNotSupportedException.Таблица 25.2. Методы, определенные в интерфейсе IListСвойство Назначениеint Count { get; } Содержит количество элементов в коллекции на данный моментbool IsSynchronized { get; } Принимает логическое значение true, если коллекция синхронизирована, а иначе — логическое значение false. По умолчанию коллекции не синхронизированы. Но для большинства коллекций можнополучить синхронизированный вариантobject SyncRoot { get; } Содержит объект, для которого коллекция можетбыть синхронизированаМетод Описаниеint Add(object value) Добавляет объект value в вызывающую коллекцию.Возвращает индекс, по которому этот объект сохраняетсяvoid Clear() Удаляет все элементы из вызывающей коллекцииbool Contains (object value) Возвращает логическое значение true, если вызывающая коллекция содержит объект value, а иначе — логическое значение falseОкончание табл. 25.2Объекты добавляются в коллекцию типа IList вызовом метода Add(). Обратите внимание на то, что метод Add() принимает аргумент типа object. А посколькуobject является базовым классом для всех типов, то в необобщенной коллекции может быть сохранен объект любого типа, включая и типы значений, в силу автоматической упаковки и распаковки.Для удаления элемента из коллекции служат методы Remove() и RemoveAt(). В частности, метод Remove() удаляет указанный объект, а метод RemoveAt() удаляет объектпо указанному индексу. И для опорожнения коллекции вызывается метод Clear().Для того чтобы выяснить, содержится ли в коллекции конкретный объект, вызывается метод Contains(). Для получения индекса объекта вызывается метод IndexOf(),а для вставки элемента в коллекцию по указанному индексу — метод Insert().В интерфейсе IList определяются следующие свойства.bool IsFixedSize { get; }bool IsReadOnly { get; }Если коллекция имеет фиксированный размер, то свойство IsFixedSize содержитлогическое значение true. Это означает, что в такую коллекцию нельзя ни вставлятьэлементы, ни удалять их из нее. Если же коллекция доступна только для чтения, тосвойство IsReadOnly содержит логическое значение true. Это означает, что содержимое такой коллекции не подлежит изменению.Кроме того, в интерфейсе IList определяется следующий индексатор.object this[int index] { get; set; }Этот индексатор служит для получения и установки значения элемента коллекции.Но его нельзя использовать для добавления в коллекцию нового элемента. С этой целью обычно вызывается метод Add(). Как только элемент будет добавлен в коллекцию,он станет доступным посредством индексатора.Метод Описаниеint IndexOf(object value) Возвращает индекс объекта value, если этот объектсодержится в вызывающей коллекции. Если жеобъект value не обнаружен, то метод возвращаетзначение -1void Insert(int index,object value)Вставляет в вызывающую коллекцию объект valueпо индексу index. Элементы, находившиеся до этого по индексу index и дальше, смещаются вперед,чтобы освободить место для вставляемого объектаvaluevoid Remove(object value) Удаляет первое вхождение объекта value в вызывающей коллекции. Элементы, находившиеся до этогоза удаленным элементом, смещаются назад, чтобыустранить образовавшийся “пробел"void RemoveAt(int index) Удаляет из вызывающей коллекции объект, расположенный по указанному индексу index. Элементы,находившиеся до этого за удаленным элементом,смещаются назад, чтобы устранить образовавшийся“пробел”Интерфейс IDictionaryВ интерфейсе IDictionary определяется такое поведение необобщенной коллекции, которое позволяет преобразовать уникальные ключи в соответствующие значения. Ключ представляет собой объект, с помощью которого значение извлекаетсявпоследствии. Следовательно, в коллекции, реализующей интерфейс IDictionary,хранятся пары "ключ-значение". Как только подобная пара будет сохранена, ее можно извлечь с помощью ключа. Интерфейс IDictionary наследует от интерфейсовICollection и IEnumerable. Методы, объявленные в интерфейсе IDictionary, сведены в табл. 25.3. Некоторые из них генерируют исключение ArgumentNullExceptionпри попытке указать пустой ключ, поскольку пустые ключи не допускаются.Таблица 25.3. Методы, определенные в интерфейсе IDictionaryДля добавления пары "ключ-значение" в коллекцию типа IDictionary служитметод Add(). Обратите внимание на то, что ключ и его значение указываются отдельно. А для удаления элемента из коллекции следует указать ключ этого объекта привызове метода Remove(). И для опорожнения коллекции вызывается метод Clear().Для того чтобы выяснить, содержит ли коллекция конкретный объект, вызывается метод Contains() с указанным ключом искомого элемента. С помощью метода GetEnumerator() получается перечислитель, совместимый с коллекцией типаIDictionary. Этот перечислитель оперирует парами "ключ-значение".В интерфейсе IDictionary определяются перечисленные ниже свойства.Следует иметь в виду, что ключи и значения, содержащиеся в коллекции, доступныв отдельных списках с помощью свойств Keys и Values.Кроме того, в интерфейсе IDictionary определяется следующий индексатор.object this[object key] { get; set; }Метод Описаниеvoid Add(object key,object value)void Clear()Добавляет в вызывающую коллекцию пару "ключ-значение”, определяемую параметрами key и valueУдаляет все пары "ключ-значение" из вызывающейколлекцииbool Contains(object key) Возвращает логическое значение true, если вызывающая коллекция содержит объект key в качестве ключа,в противном случае — логическое значение falseIDictionaryEnumeratorGetEnumerator()Возвращает перечислитель для вызывающей коллекцииvoid Remove(object key) Удаляет из коллекции элемент, ключ которого равен значению параметра keyСвойство Назначениеbool IsFixedSize { get; } Принимает логическое значение true, если словарьимеет фиксированный размерbool IsReadOnly { get; } Принимает логическое значение true, если словарь доступен только для чтенияICollection Keys { get; } Получает коллекцию ключейICollection Values { get; } Получает коллекцию значенийЭтот индексатор служит для получения и установки значения элемента коллекции,а также для добавления в коллекцию нового элемента. Но в качестве индекса в данномслучае служит ключ элемента, а не собственно индекс.Интерфейсы IEnumerable, IEnumerator и IDictionaryEnumeratorИнтерфейс IEnumerable является необобщенным, и поэтому он должен бытьреализован в классе для поддержки перечислителей. Как пояснялось выше, интерфейс IEnumerable реализуется во всех классах необобщенных коллекций, поскольку он наследуется интерфейсом ICollection. Ниже приведен единственный методGetEnumerator(), определяемый в интерфейсе IEnumerable.IEnumerator GetEnumerator()Он возвращает коллекцию. Благодаря реализации интерфейса IEnumerable можно также получать содержимое коллекции в цикле foreach.В интерфейсе IEnumerator определяются функции перечислителя. С помощью методов этого интерфейса можно циклически обращаться к содержимому коллекции. Еслив коллекции содержатся пары "ключ-значение" (словари), то метод GetEnumerator()возвращает объект типа IDictionaryEnumerator, а не типа IEnumerator. ИнтерфейсIDictionaryEnumerator наследует от интерфейса IEnumerator и вводит дополнительные функции, упрощающие перечисление словарей.В интерфейсе IEnumerator определяются также методы MoveNext() и Reset()и свойство Current. Способы их применения подробнее описываются далее в этойглаве. А до тех пор следует отметить, что свойство Current содержит элемент, получаемый в текущий момент. Метод MoveNext() осуществляет переход к следующемуэлементу коллекции, а метод Reset() возобновляет перечисление с самого начала.Интерфейсы IComparer и IEqualityComparerВ интерфейсе IComparer определяется метод Compare() для сравнения двухобъектов.int Compare(object х, object у)Он возвращает положительное значение, если значение объекта х больше, чем уобъекта у; отрицательное — если значение объекта х меньше, чем у объекта у; и нулевое — если сравниваемые значения равны. Данный интерфейс можно использоватьдля указания способа сортировки элементов коллекции.В интерфейсе IEqualityComparer определяются два метода.bool Equals(object х, object у)int GetHashCode(object obj)Метод Equals() возвращает логическое значение true, если значения объектов хи у равны. А метод GetHashCode() возвращает хеш-код для объекта obj.Интерфейсы IStructuralComparable и IStructuralEquatableОба интерфейса IStructuralComparable и IStructuralEquatable добавлены вверсию 4.0 среды .NET Framework. В интерфейсе IStructuralComparable определяется метод CompareTo(), который задает способ структурного сравнения двух объектовдля целей сортировки. (Иными словами, Метод CompareTo() сравнивает содержимоеобъектов, а не ссылки на них.) Ниже приведена форма объявления данного метода.int CompareTo(object other, IComparer comparer)Он должен возвращать -1, если вызывающий объект предшествует другому объектуother; 1, если вызывающий объект следует после объекта other; и наконец, 0, еслизначения обоих объектов одинаковы для целей сортировки. А само сравнение обеспечивает объект, передаваемый через параметр comparer.Интерфейс IStructuralEquatable служит для выяснения структурного равенства путем сравнения содержимого двух объектов. В этом интерфейсе определены следующие методы.bool Equals(object other, IEqualityComparer comparer)int GetHashCode(IEqualityComparer comparer)Метод Equals() должен возвращать логическое значение true, если вызывающийобъект и другой объект other равны. А метод GetHashCode() должен возвращатьхеш-код для вызывающего объекта. Результаты, возвращаемые обоими методами,должны быть совместимы. Само сравнение обеспечивает объект, передаваемый черезпараметр comparer.Структура DictionaryEntryВ пространстве имен System.Collections определена структура DictionaryEntry.Необобщенные коллекции пар "ключ-значение" сохраняют эти пары в объекте типаDictionaryEntry. В данной структуре определяются два следующих свойства.public object Key { get; set; }public object Value { get; set; }Эти свойства служат для доступа к ключу или значению, связанному с элементомколлекции. Объект типа DictionaryEntry может быть сконструирован с помощьюконструктора:public DictionaryEntry(object key, object value)где key обозначает ключ, a value — значение.Классы необобщенных коллекцийА теперь, когда представлены интерфейсы необобщенных коллекций, можно перейти к рассмотрению стандартных классов, в которых они реализуются. Ниже приведены классы необобщенных коллекций, за исключением коллекции типа BitArray,рассматриваемой далее в этой главе.Класс ОписаниеArrayList Определяет динамический массив, т.е. такой массив, который может принеобходимости увеличивать свой размерHashtable Определяет хеш-таблицу для пар “ключ-значение”Queue Определяет очередь, или список, действующий по принципу “первым пришел — первым обслужен”SortedList Определяет отсортированный список пар “ключ-значение”Stack Определяет стек, или список, действующий по принципу "первым пришел —последним обслужен”Каждый из этих классов коллекций подробно рассматривается и демонстрируетсядалее на конкретных примерах.Класс ArrayListВ классе ArrayList поддерживаются динамические массивы, расширяющиеся исокращающиеся по мере необходимости. В языке C# стандартные массивы имеют фиксированную длину, которая не может изменяться во время выполнения программы.Это означает, что количество элементов в массиве нужно знать заранее. Но иногда требуемая конкретная длина массива остается неизвестной до самого момента выполнения программы. Именно для таких ситуаций и предназначен класс ArrayList. В классе ArrayList определяется массив переменной длины, который состоит из ссылок наобъекты и может динамически увеличивать и уменьшать свой размер. Массив типаArrayList создается с первоначальным размером. Если этот размер превышается, томассив автоматически расширяется. А при удалении объектов из такого массива онавтоматически сокращается. Коллекции класса ArrayList широко применяются впрактике программирования на С#. Именно поэтому они рассматриваются здесь подробно. Но многие способы применения коллекций класса ArrayList распространяются и на другие коллекции, в том числе и на обобщенные.В классе ArrayList реализуются интерфейсы ICollection, IList, IEnumerableи ICloneable. Ниже приведены конструкторы класса ArrayList.public ArrayList()public ArrayList(ICollection c)public ArrayList(int capacity)Первый конструктор создает пустую коллекцию класса ArrayList с нулевой первоначальной емкостью. Второй конструктор создает коллекцию типа ArrayList с количеством инициализируемых элементов, которое определяется параметром с и равнопервоначальной емкости массива. Третий конструктор создает коллекцию, имеющуюуказанную первоначальную емкость, определяемую параметром сараcity. В данномслучае емкость обозначает размер базового массива, используемого для хранения элементов коллекции. Емкость коллекции типа ArrayList может увеличиваться автоматически по мере добавления в нее элементов.В классе ArrayList определяется ряд собственных методов, помимо тех, что ужеобъявлены в интерфейсах, которые в нем реализуются. Некоторые из наиболее частоиспользуемых методов класса ArrayList перечислены в табл. 25.4. Коллекцию классаArrayList можно отсортировать, вызвав метод Sort(). В этом случае поиск в отсортированной коллекции с помощью метода BinarySearch() становится еще болееэффективным. Содержимое коллекции типа ArrayList можно также обратить, вызвав метод Reverse().Таблица 25.4. Наиболее часто используемые методы, определенные в классе ArrayListМетод Описаниеpublic virtual voidAddRange(Icollection с)public virtual intBinarySearch(objectvalue)Добавляет элементы из коллекции с в конец вызывающей коллекции типа ArrayListВыполняет поиск в вызывающей коллекции значенияvalue. Возвращает индекс найденного элемента. Еслиискомое значение не найдено, возвращает отрицательное значение. Вызывающий список должен быть отсортированПродолжение табл. 25.4Метод Описаниеpublic virtual intBinarySearch(objectvalue, Icomparercomparer)Выполняет поиск в вызывающей коллекции значенияvalue, используя для сравнения способ, определяемыйпараметром comparer. Возвращает индекс совпавшего элемента. Если искомое значение не найдено, возвращает отрицательное значение. Вызывающий списокдолжен быть отсортированpublic virtual intBinarySearch(int index,int count, object value,IComparer comparer)Выполняет поиск в вызывающей коллекции значенияvalue, используя для сравнения способ, определяемыйпараметром comparer. Поиск начинается с элемента,указываемого по индексу index, и включает количествоэлементов, определяемых параметром count. Метод возвращает индекс совпавшего элемента. Если искомое значение не найдено, метод возвращает отрицательное значение. Вызывающий список должен быть отсортированpublic virtual voidСоруТо(Array array)Копирует содержимое вызывающей коллекции в массив array, который должен быть одномерным и совместимым по типу с элементами коллекцииpublic virtual voidСоруТо(Array array, intarrayIndex)Копирует содержимое вызывающей коллекции в массивarray, начиная с элемента, указываемого по индексуarrayIndex. Целевой массив должен быть одномерным и совместимым по типу с элементами коллекцииpublic virtual voidCopyTo(int index, Arrayarray, int arrayIndex,int count)Копирует часть вызывающей коллекции, начиная с элемента, указываемого по индексу index, и включая количество элементов, определяемых параметром count,в массив array, начиная с элемента, указываемого поиндексу arrayIndex. Целевой массив должен быть одномерным и совместимым по типу с элементами коллекцииpublic static ArrayListFixedSize(ArrayList list)public virtual ArrayListGetRange(int index, intcount)Заключает коллекцию list в оболочку типа ArrayListс фиксированным размером и возвращает результатВозвращает часть вызывающей коллекции типаArrayList. Часть возвращаемой коллекции начинается с элемента, указываемого по индексу index, и включает количество элементов, определяемое параметромcount. Возвращаемый объект ссылается на те же элементы, что и вызывающий объектpublic virtual intIndexOf(object value)Возвращает индекс первого вхождения объекта valueв вызывающей коллекции. Если искомый объект не обнаружен, возвращает значение -1public virtual voidInsertRange(int index,ICollection c)Вставляет элементы коллекции с в вызывающую коллекцию, начиная с элемента, указываемого по индексуindexpublic virtual intLastlndexOf(object value)Возвращает индекс последнего вхождения объектаvalue в вызывающей коллекции. Если искомый объектне обнаружен, метод возвращает значение -1Окончание табл. 25.4В классе ArrayList поддерживается также ряд методов, оперирующих элементами коллекции в заданных пределах. Так, в одну коллекцию типа ArrayList можновставить другую коллекцию, вызвав метод InsertRange(). Для удаления из коллекции элементов в заданных пределах достаточно вызвать метод RemoveRange(). А дляМетод Описаниеpublic static ArrayListReadonly(ArrayList list)Заключает коллекцию list в оболочку типаArrayList, доступную только для чтения, и возвращает результатpublic virtual voidRemoveRange(int index,int count)Удаляет часть вызывающей коллекции, начиная с элемента, указываемого по индексу index, и включаяколичество элементов, определяемое параметромcountpublic virtual voidReverse()Располагает элементы вызывающей коллекции в обратном порядкеpublic virtual voidReverse(int index, intcount)Располагает в обратном порядке часть вызывающейколлекции, начиная с элемента, указываемого по индексу index, и включая количество элементов, определяемое параметром countpublic virtual voidSetRange(int index,ICollection c)Заменяет часть вызывающей коллекции, начиная с элемента, указываемого по индексу index, элементамиколлекции сpublic virtual voidSort()Сортирует вызывающую коллекцию по нарастающейpublic virtual voidSort(Icomparer comparer)Сортирует вызывающую коллекцию, используя для сравнения способ, определяемый параметром comparer.Если параметр comparer имеет пустое значение, тодля сравнения используется способ, выбираемый поумолчаниюpublic virtual voidSort(int index, intcount, Icomparercomparer)Сортирует вызывающую коллекцию, используя для сравнения способ, определяемый параметром comparer.Сортировка начинается с элемента, указываемого поиндексу index, и включает количество элементов,определяемых параметром count. Если параметрcomparer имеет пустое значение, то для сравнения используется способ, выбираемый по умолчаниюpublic static ArrayListSynchronized(ArrayListlist)Возвращает синхронизированный вариант коллекциитипа ArrayList, передаваемой в качестве параметраlistpublic virtual object[]ToArray()Возвращает массив, содержащий копии элементов вызывающего объектаpublic virtual ArrayToArray(Type type)Возвращает массив, содержащий копии элементов вызывающего объекта. Тип элементов этого массива определяется параметром typepublic virtual voidTrimToSize()Устанавливает значение свойства Capacity равнымзначению свойства Countперезаписи элементов коллекции типа ArrayList в заданных пределах элементамииз другой коллекции служит метод SetRange(). И наконец, элементы коллекцииможно сортировать или искать в заданных пределах, а не во всей коллекции.По умолчанию коллекция типа ArrayList не синхронизирована. Для получениясинхронизированной оболочки, в которую заключается коллекция, вызывается методSynchronized().В классе ArrayList имеется также приведенное ниже свойство Capacity, помимосвойств, определенных в интерфейсах, которые в нем реализуются.public virtual int Capacity { get; set; }Свойство Capacity позволяет получать и устанавливать емкость вызывающей коллекции типа ArrayList. Емкость обозначает количество элементов, которые можетсодержать коллекция типа ArrayList до ее вынужденного расширения. Как упоминалось выше, коллекция типа ArrayList расширяется автоматически, и поэтому задавать ее емкость вручную необязательно. Но из соображений эффективности это иногда можно сделать, если количество элементов коллекции известно заранее. Благодаряэтому исключаются издержки на выделение дополнительной памяти.С другой стороны, если требуется сократить размер базового массива коллекциитипа ArrayList, то для этой цели достаточно установить меньшее значение свойстваCapacity. Но это значение не должно быть меньше значения свойства Count. Напомним, что свойство Count определено в интерфейсе ICollection и содержит количество объектов, хранящихся в коллекции на данный момент. Всякая попытка установитьзначение свойства Capacity меньше значения свойства Count приводит к генерированию исключения ArgumentOutOfRangeException. Поэтому для получения такогоколичества элементов коллекции типа ArrayList, которое содержится в ней на данный момент, следует установить значение свойства Capacity равным значению свойства Count. Для этой цели можно также вызвать метод TrimToSize().В приведенном ниже примере программы демонстрируется применение классаArrayList. В ней сначала создается коллекция типа ArrayList, а затем в эту коллекцию вводятся символы, после чего содержимое коллекции отображается. Некоторыеэлементы затем удаляются из коллекции, и ее содержимое отображается вновь. Послеэтого в коллекцию вводятся дополнительные элементы, что вынуждает увеличить ееемкость. И наконец, содержимое элементов коллекции изменяется.// Продемонстрировать применение класса ArrayList.using System;using System.Collections;class ArrayListDemo {static void Main() {// Создать коллекцию в виде динамического массива.ArrayList al = new ArrayList();Console.WriteLine("Исходное количество элементов: " + al.Count);Console.WriteLine();Console.WriteLine("Добавить 6 элементов");// Добавить элементы в динамический массив.al.Add('С');al.Add('A');al.Add('E');al.Add('В');al.Add('D');al.Add('F');Console.WriteLine("Количество элементов: " + al.Count);// Отобразить содержимое динамического массива,// используя индексирование массива.Console.Write("Текущее содержимое: ");for(int i=0; i < al.Count; i++)Console.Write(al[i] + " ");Console.WriteLine("n");Console.WriteLine("Удалить 2 элемента");// Удалить элементы из динамического массива.al.Remove('F');al.Remove('A');Console.WriteLine("Количество элементов: " + al.Count);// Отобразить содержимое динамического массива, используя цикл foreach.Console.Write("Содержимое: ");foreach(char с in al)Console.Write(с + " ");Console.WriteLine("n");Console.WriteLine("Добавить еще 20 элементов");// Добавить количество элементов, достаточное для// принудительного расширения массива.for (int i=0; i < 20; i++)al.Add((char)('a' + i));Console.WriteLine("Текущая емкость: " + al.Capacity);Console.WriteLine("Количество элементов после добавления 20 новых: " +al.Count);Console.Write("Содержимое: ");foreach(char с in al)Console.Write(с + " ");Console.WriteLine("n");// Изменить содержимое динамического массива,// используя индексирование массива.Console.WriteLine("Изменить три первых элемента");al[0] = 'X';al[1] = 'Y';al[2] = 'Z';Console.Write("Содержимое: ");foreach(char с in al)Console.Write(c + "Console.WriteLine();}}Вот к какому результату приводит выполнение этой программы.Исходное количество элементов: 0Добавить 6 элементовКоличество элементов: 6Текущее содержимое: С А Е В D FУдалить 2 элементаКоличество элементов: 4Содержимое: С Е В DДобавить еще 20 элементовТекущая емкость: 32Количество элементов после добавления 20 новых: 24Содержимое: C E B D a b c d e f g h i j k l m n o p q r s tИзменить три первых элементаСодержимое: X Y Z D a b c d e f g h i j k l m n o p q r s tСортировка и поиск в коллекции типа ArrayListКоллекцию типа ArrayList можно отсортировать с помощью метода Sort().В этом случае поиск в отсортированной коллекции с помощью метода BinarySearch()становится еще более эффективным. Применение обоих методов демонстрируетсяв приведенном ниже примере программы.// Отсортировать коллекцию типа ArrayList и осуществить в ней поиск.using System;using System.Collections;class SortSearchDemo {static void Main() {// Создать коллекцию в виде динамического массива.ArrayList al = new ArrayList();// Добавить элементы в динамический массив.al.Add(55);al.Add(43);al.Add(-4);al.Add(88);al.Add(3);al.Add(19);Console.Write("Исходное содержимое: ");foreach(int i in al)Console.Write(i + " ");Console.WriteLine("n");// Отсортировать динамический массив.al.Sort();// Отобразить содержимое динамического массива, используя цикл foreach.Console.Write("Содержимое после сортировки: ");foreach(int i in al)Console.Write(i + " ");Console.WriteLine("n");Console.WriteLine("Индекс элемента 43: " +al.BinarySearch(43));}}Ниже приведен результат выполнения этой программы.Исходное содержимое: 55 43 -4 88 3 19Содержимое после сортировки: -4 3 19 43 55 88Индекс элемента 43: 3В одной и той же коллекции типа ArrayList могут храниться объекты любоготипа. Тем не менее во время сортировки и поиска в ней эти объекты приходится сравнивать. Так, если бы список объектов в приведенном выше примере программы содержал символьную строку, то их сравнение привело бы к исключительной ситуации.Впрочем, для сравнения символьных строк и целых чисел можно создать специальныеметоды. О таких методах сравнения речь пойдет далее в этой главе.Получение массива из коллекции типа ArrayListВ работе с коллекцией типа ArrayList иногда требуется получить из ее содержимого обычный массив. Этой цели служит метод ТоАrrау(). Для преобразованияколлекции в массив имеется несколько причин. Две из них таковы: потребность в ускорении обработки при выполнении некоторых операций и необходимость передаватьмассив методу, который не перегружается, чтобы принять коллекцию. Но независимоот конкретной причины коллекция типа ArrayList преобразуется в обычный массивдовольно просто, как показано в приведенном ниже примере программы.// Преобразовать коллекцию типа ArrayList в обычный массив.using System;using System.Collections;class ArrayListToArray {static void Main() {ArrayList al = new ArrayList();// Добавить элементы в динамический массив.al.Add(1);al.Add(2);al.Add(3);al.Add(4);Console.Write("Содержимое: ");foreach(int i in al)Console.Write(i + " ");Console.WriteLine();// Получить массив.int[] ia = (int[]) al.ToArray(typeof(int));int sum = 0;// Просуммировать элементы массива.for(int i=0; i ");int a = (int) st.Pop();Метод Описаниеpublic virtual void Clear() Устанавливает свойство Count равным нулю, очищая, по существу, стекpublic virtual boolContains (object obj)Возвращает логическое значение true, если объектobj содержится в вызывающем стеке, а иначе —логическое значение falsepublic virtual object Peek() Возвращает элемент, находящийся на вершине стека, но не удаляет егоpublic virtual object Pop() Возвращает элемент, находящийся на вершине стека, удаляя его по ходу делаpublic virtual voidPush (object obj)Помещает объект obj в стекpublic static StackSynchronized(Stack stack)Возвращает синхронизированный вариант коллекции типа Stack, передаваемой в качестве параметра stackpublic virtual object[]ToArray()Возвращает массив, содержащий копии элементоввызывающего стекаConsole.WriteLine(a);Console.Write("Содержимое стека: ");foreach(int i in st)Console.Write(i + " ");Console.WriteLine();}static void Main() {Stack st = new Stack ();foreach(int i in st)Console.Write(i + " ");Console.WriteLine();ShowPush(st, 22);ShowPush(st, 65);ShowPush(st, 91);ShowPop(st);ShowPop(st);ShowPop(st);try {ShowPop(st);} catch (InvalidOperationException) {Console.WriteLine("Стек пуст.");}}}Ни