Выбрать главу
рвоначальный размер которой определяет емкость, задаваемая параметром сараcity, а коэффициент роста по умолчанию выбирается для нее равным 2,0. В тре тьей форме допускается указывать не только емкость (в качестве параметра capacity), но и коэффициент роста создаваемой очереди (в качестве параметра growFactor в пределах от 1,0 до 10,0). И в четвертой форме создается очередь, состоящая из элемен тов указываемой коллекции col. Ее первоначальная емкость равна количеству указан ных элементов, а коэффициент роста по умолчанию выбирается для нее равным 2,0. В классе Queue определяется ряд собственных методов, помимо тех, что уже объявлены в интерфейсах, которые в нем реализуются. Некоторые из наиболее ча сто используемых методов этого класса перечислены в табл. 25.8. Эти методы обыч но применяются следующим образом. Для того чтобы поместить объект в очередь, вызывается метод Enqueue(). Если требуется извлечь и удалить первый объект из начала очереди, то вызывается метод Dequeue(). Если же требуется извлечь, но не удалять следующий объект из очереди, то вызывается метод Рееk(). А если методы Dequeue() и Рееk() вызываются, когда очередь пуста, то генерируется исключение InvalidOperationException. Таблица 25.8. Наиболее часто используемые методы, определенные в классе Queue Метод Описание public virtual void Clear() Устанавливает свойство Count равным нулю, очи щая, по существу, очередь public virtual bool Contains(object obj) Возвращает логическое значение true, если объ ект obj содержится в вызывающей очереди, а ина че — логическое значение false public virtual object Dequeue() public virtual void Enqueue(object obj) Возвращает объект из начала вызывающей очере ди. Возвращаемый объект удаляется из очереди Добавляет объект obj в конец очереди Окончание табл. 25.8 Метод Описание public virtual object Peek() Возвращает объект из начала вызывающей очере ди, но не удаляет его public static Queue Synchronized(Queue queue) Возвращает синхронизированный вариант коллек ции типа Queue, передаваемой в качестве параме тра queue public virtual object[] ToArray() Возвращает массив, который содержит копии эле ментов из вызывающей очереди public virtual void TrimToSize() Устанавливает значение свойства Capacity рав ным значению свойства Count В приведенном ниже примере программы демонстрируется применение класса Queue. // Продемонстрировать применение класса Queue. using System; using System.Collections; class QueueDemo { static void ShowEnq(Queue q, int a) { q.Enqueue(a); Console.WriteLine("Поместить в очередь: Enqueue(" + a + ")"); Console.Write("Содержимое очереди: "); foreach(int i in q) Console.Write(i + " "); Console.WriteLine (); } static void ShowDeq(Queue q) { Console.Write("Извлечь из очереди: Dequeue -> "); int a = (int) q.Dequeue(); Console.WriteLine(a); Console.Write("Содержимое очереди: "); foreach(int i in q) Console.Write(i + " "); Console.WriteLine(); } static void Main() { Queue q = new Queue(); foreach(int i in q) Console.Write(i + " "); Console.WriteLine(); ShowEnq(q, 22); ShowEnq(q, 65); ShowEnq(q, 91); ShowDeq(q); ShowDeq(q); ShowDeq(q); try { ShowDeq (q); } catch (InvalidOperationException) { Console.WriteLine("Очередь пуста."); } } } Эта программа дает следующий результат. Поместить в очередь: Enqueue(22) Содержимое очереди: 22 Поместить в очередь: Enqueue(65) Содержимое очереди: 22 65 Поместить в очередь: Enqueue(91) Содержимое очереди: 22 65 91 Извлечь из очереди: Dequeue -> 22 Содержимое очереди: 65 91 Извлечь из очереди: Dequeue -> 65 Содержимое очереди: 91 Извлечь из очереди: Dequeue -> 91 Содержимое очереди: Извлечь из очереди: Dequeue -> Очередь пуста. Хранение отдельных битов в классе коллекции BitArray Класс BitArray служит для хранения отдельных битов в коллекции. А поскольку в коллекции этого класса хранятся биты, а не объекты, то своими возможностями он отличается от классов других коллекций. Тем не менее в классе BitArray реализуют ся интерфейсы ICollection и IEnumerable как основополагающие элементы под держки всех типов коллекций. Кроме того, в классе BitArray реализуется интерфейс ICloneable. В классе BitArray определено несколько конструкторов. Так, с помощью приве денного ниже конструктора можно сконструировать объект типа BitArray из массива логических значений. public BitArray(bool[] values) В данном случае каждый элемент массива values становится отдельным битом в коллекции. Это означает, что каждому элементу массива values соответствует отдель ный бит в коллекции. Более того, порядок расположения элементов в массиве values сохраняется и в коллекции соответствующих им битов. Коллекцию типа BitArray можно также составить из массива байтов, используя следующий конструктор. public BitArray(byte[] bytes) Здесь битами в коллекции становится уже целый их набор из массива bytes, при чем элемент bytes[0] обозначает первые 8 битов, элемент bytes[1] — вторые 8 би тов и т.д. Аналогично, коллекцию типа BitArray можно составить из массива цело численных значений, используя приведенный ниже конструктор. public BitArray(int[ ] values) В данном случае элемент values[0] обозначает первые 32 бита, элемент values[1] — вторые 32 бита и т.д. С помощью следующего конструктора можно составить коллекцию типа BitArray, указав ее конкретный размер: public BitArray(int length) где length обозначает количество битов в коллекции, которые инициализируются логическим значением false. В приведенном ниже конструкторе можно указать не только размер коллекции, но и первоначальное значение составляющих ее битов. public BitArray(int length, bool defaultValue) В данном случае все биты в коллекции инициализируются значением defaultValue, передаваемым конструктору в качестве параметра. И наконец, новую коллекцию типа BitArray можно создать из уже существую щей, используя следующий конструктор. public BitArray(BitArray bits) Вновь сконструированный объект будет содержать такое же количество битов, как и в указываемой коллекции bits, а в остальном это будут две совершенно разные кол лекции. Коллекции типа BitArray подлежат индексированию. По каждому индексу указы вается отдельный бит в коллекции, причем нулевой индекс обозначает младший бит. В классе BitArray определяется ряд собственных методов, помимо тех, что уже объявлены в интерфейсах, которые в нем реализуются. Методы этого класса приведе ны в табл. 25.9. Обратите внимание на то, что в классе BitArray не поддерживается метод Synchronized(). Это означает, что для коллекций данного класса синхронизи рованная оболочка недоступна, а свойство IsSynchronized всегда имеет логическое значение false. Тем не менее для управления доступом к коллекции типа BitArray ее можно синхронизировать для объекта, предоставляемого упоминавшимся ранее свойством SyncRoot. Таблица 25.9. Методы, определенные в классе BitArray Метод Описание public BitArray And(BitArray value) Выполняет операцию логического умножения И би тов вызывающего объекта и коллекции value. Воз вращает коллекцию типа BitArray, содержащую результат public bool Get(int index) Возвращает значение бита, указываемого по ин дексу index public BitArray Not() Выполняет операцию поразрядного логического отри цания НЕ битов вызывающей коллекции и возвраща ет коллекцию типа BitArray, содержащую результат Окончание табл. 25.9 В классе BitArray определяется также собственное свойство, помимо тех, что ука заны в интерфейсах, которые в нем реализуются. public int Length { get; set; } Свойство Length позволяет установить или получить количество битов в коллек ции. Следовательно, оно возвращает такое же значение, как и стандартное свойство Count, определяемое для всех коллекций. В отличие от свойства Count, свойство Length доступно не только для чтения, но и для записи, а значит, с его помощью мож но изменить размер коллекции типа BitArray. Так, при сокращении коллекции типа BitArray лишние биты усекаются, начиная со старшего разряда. А при расширении коллекции типа BitArray дополнительные биты, имеющие логическое значение false, вводятся в коллекцию, начиная с того же старшего разряда. Кроме того, в классе BitArray определяется следующий индексатор. public bool this[int index] { get; set; } С помощью этого индексатора можно получать или устанавливать значение элемента. В приведенном ниже примере демонстрируется применение класса BitArray. // Продемонстрировать применение класса BitArray. using System; using System.Collections; class BADemo { public static void ShowBits(string rem, BitArray bits) { Console.WriteLine(rem); for(int i=0; i < bits.Count; i++) Console.Write("{0, -6} ", bits[i]); Console.WriteLine("\n"); } static void Main() { BitArray ba = new BitArray(8); byte[] b = { 67 }; BitArray ba2 = new BitArray(b); Метод Описание public BitArray Or(BitArray value) Выполняет операцию логического сложения ИЛИ би тов вызывающего объекта и коллекции value. Воз вращает коллекцию типа BitArray, содержащую результат public void Set(int index, bool value) Устанавливает бит, указываемый по индексу Index, равным значению value public void SetAll(bool value) Устанавливает все биты равными значению value public BitArray Xor(BitArray value) Выполняет логическую операцию исключающее ИЛИ над битами вызывающего объекта и коллекции value. Возвращает коллекцию типа BitArray, со держащую результат ShowBits("Исходное содержимое коллекции ba:", bа); ba = ba.Not(); ShowBits("Содержимое коллекции bа после логической операции NOT:", ba); ShowBits("Содержимое коллекции bа2:", bа2); BitArray bа3 = bа.Хоr(bа2); ShowBits("Результат логической операции ba XOR bа2:", bаЗ); } } Эта программа дает следующий результат. Исходное содержимое коллекции Ьа: False False False False False False False False Содержимое коллекции ba после логической операции NOT: True True True True True True True True Содержимое коллекции bа2: True True False False False False ffrue False Результат логической операции ba XOR ba2: False False True True True True False True Специальные коллекции В среде .NET Framework предусмотрен ряд специальных коллекций, оптимизиро ванных для работы с данными конкретного типа иди для их обработки особым обра зом. Классы этих необобщенных коллекций определены в пространстве имен System. Collections.Specialized и перечислены ниже. Класс специальной коллекции Описание CollectionsUtil Содержит фабричные методы для создания коллекций HybridDictionary Предназначен для коллекций, в которых для хранения неболь шого количества пар “ключ-значение" используется класс ListDictionary. При превышении коллекцией определен ного размера автоматически используется класс Hashtable для хранения ее элементов ListDictionary Предназначен для коллекций, в которых для хранения пар “ключ- значение” используется связный список. Такие коллекции реко мендуются только для хранения небольшого количества элементов NameValueCollection Предназначен для отсортированных коллекций, в которых хра нятся пары “ключ-значение”, причем и ключ, и значение от носятся к типу 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 имеется одно ва