программирование. Руководство su P# a n Reference в herbert schildt полное руководство с 0 герберт шилдт
Скачать 3.32 Mb.
|
ГЛАВА 25 Коллекции, перечислители и итераторы В этой главе речь пойдет об одной из самых важных составляющих среды .NET Framework: коллекциях. В C# коллекция представляет собой совокупность объектов. В среде .NET Framework имеется немало интерфейсов и классов, в которых определяются и реализуются различные типы коллекций. Коллекции упрощают решение многих задач программирования благодаря тому, что предлагают готовые решения для создания целого ряда типичных, но порой трудоемких для разработки структур данных. Например, в среду .NET Framework встроены коллекции, предназначенные для поддержки динамических массивов, связных списков, стеков, очередей и хеш‑таблиц. Коллекции являются современным технологическим средством, заслуживающим пристального внимания всех, кто программирует на С#. Первоначально существовали только классы необобщенных коллекций. Но с внедрением обобщений в версии C# 2.0 среда .NET Framework была дополнена многими новыми обобщенными классами и интерфейсами. Благодаря введению обобщенных коллекций общее количество классов и интерфейсов удвоилось. Вместе с библиотекой распараллеливания задач (TPL) в версии 4.0 среды .NET Framework появился ряд новых классов коллекций, предназначенных для применения в тех случаях, когда доступ к коллекции осуществляется из нескольких потоков. Нетрудно догадаться, что прикладной интерфейс Collections API составляет значительную часть среды .NET Framework. Кроме того, в настоящей главе рассматриваются два средства, непосредственно связанные с коллекциями: перечислители и итераторы. И те и другие позволяют поочередно обращаться к содержимому класса коллекции в цикле foreach. Краткий обзор коллекций Главное преимущество коллекций заключается в том, что они стандартизируют обработку групп объектов в программе. Все коллекции разработаны на основе набора четко определенных интерфейсов. Некоторые встроенные реализации таких интерфейсов, в том числе ArrayList, Hashtable, Stack и Queue, могут применяться в исходном виде и без каких‑либо изменений. Имеется также возможность реализовать собственную коллекцию, хотя потребность в этом возникает крайне редко. В среде .NET Framework поддерживаются пять типов коллекций: необобщенные, специальные, с поразрядной организацией, обобщенные и параллельные. Необобщен‑ные коллекции реализуют ряд основных структур данных, включая динамический массив, стек, очередь, а также словари, в которых можно хранить пары "ключ‑значение". В отношении необобщенных коллекций важно иметь в виду следующее: они оперируют данными типа obj ect. Таким образом, необобщенные коллекции могут служить для хранения данных любого типа, причем в одной коллекции допускается наличие разнотипных данных. Очевидно, что такие коллекции не типизированы, поскольку в них хранятся ссылки на данные типа object. Классы и интерфейсы необобщенных коллекций находятся в пространстве имен System.Collections. Специадьные коллекции оперируют данными конкретного типа или же делают это каким‑то особым образом. Например, имеются специальные коллекции для символьных строк, а также специальные коллекции, в которых используется однонаправленный список. Специальные коллекции объявляются в пространстве имен System. Collections.Specialized. В прикладном интерфейсе Collections API определена одна коллекция с поразрядной организацией – это Bit Array. Коллекция типа Bit Array поддерживает поразрядные операции, т.е. операции над отдельными двоичными разрядами, например И или исключающее ИЛИ, а следовательно, она существенно отличается своими возможностями от остальных типов коллекций. Коллекция типа Bit Array объявляется в пространстве имен System. Collections. Обобщенные коллекции обеспечивают обобщенную реализацию нескольких стандартных структур данных, включая связные списки, стеки, очереди и словари. Такие коллекции являются типизированными в силу их обобщенного характера. Это означает, что в обобщенной коллекции могут храниться только такие элементы данных, которые совместимы по типу с данной коллекцией. Благодаря этому исключается случайное несовпадение типов. Обобщенные коллекции объявляются в пространстве имен System.Collections.Generic. Параллельные коллекции поддерживают многопоточный доступ к коллекции. Это обобщенные коллекции, определенные в пространстве имен System. Collections . Concurrent. В пространстве имен System. Collections . Obj ectModel находится также ряд классов, поддерживающих создание пользователями собственных обобщенных коллекций. Основополагающим для всех коллекций является понятие перечислителя, который поддерживается в необобщенных интерфейсах IEnumerator и IEnumerable, а также в обобщенных интерфейсах IEnumerator Основополагающим для всех коллекций является понятие перечислителя, который поддерживается в необобщенных интерфейсах IEnumerator и IEnumerable, а также в обобщенных интерфейсах IEnumerator С перечислителем непосредственно связано другое средство, называемое итератором. Это средство упрощает процесс создания классов коллекций, например специальных, поочередное обращение к которым организуется в цикле 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 Определяет элементы, которые должны иметь все необобщенные коллекции IComparer Определяет метод Compare () для сравнения объектов, хранящихся в коллекции IDictionary Определяет коллекцию, состоящую из пар “ключ‑значение” IDictionaryEnumerator Определяет перечислитель для коллекции, реализующей интерфейс IDictionary IEnumerable Определяет метод GetEnumerator () , предоставляющий перечислитель для любого класса коллекции IEnumerator Предоставляет методы, позволяющие получать содержимое коллекции по очереди IEqualityComparer Сравнивает два объекта на предмет равенства IHashCodeProvider Считается устаревшим. Вместо него следует использовать интерфейс IEqualityComparer IList Определяет коллекцию, доступ к которой можно получить с помощью индексатора IStructuralComparable Определяет метод CompareTo () , применяемый для структурного сравнения IStructuralEquatable Определяет метод Equals () , применяемый для выяснения структурного, а не ссылочного равенства. Кроме того, определяет метод GetHashCode () Интерфейс ICollection Интерфейс ICollection служит основанием, на котором построены все необобщенные коллекции. В нем объявляются основные методы и свойства для всех необобщенных коллекций. Он также наследует от интерфейса IEnumerable. В интерфейсе ICollection определяются перечисленные ниже свойства. Свойство Count используется чаще всего, поскольку оно содержит количество элементов, хранящихся в коллекции на данный момент. Если значение свойства Count равно нулю, то коллекция считается пустой. В интерфейсе ICollection определяется следующий метод. void CopyTo(Array target , int startldx) Свойство Назначение int Count { get; } Содержит количество элементов в коллекции на дан ный момент bool isSynchronized { get; } Принимает .логическое значение true, если коллек ция синхронизирована, а иначе – логическое значение false. По умолчанию коллекции не синхронизированы. Но для большинства коллекций можно получить синхронизированный вариант object SyncRoot { get; } Содержит объект, для которого коллекция может _быть синхронизирована_ Метод CopyTo () копирует содержимое коллекции в массив target, начиная с элемента, указываемого по индексу startldx. Следовательно, метод CopyTo () обеспечивает в C# переход от коллекции к стандартному массиву. Благодаря тому что интерфейс ICollection наследует от интерфейса I Enumerable, в его состав входит также единственный метод, определенный в интерфейсе IEnumerable. Это метод GetEnumerator () , объявляемый следующим образом. IEnumerator GetEnumerator() Он возвращает перечислитель для коллекции. Вследствие того же наследования от интерфейса IEnumerable в интерфейсе ICollection определяются также четыре следующих метода расширения: AsParallel (), AsQueryable (), Cast () и Of Type (). В частности, метод AsParallel () объявляется в классе System. Linq. ParallelEnumerable, метод AsQueryable () – в классе System. Linq. Queryable, а методы Cast () и Of Type () – в классе System. Linq.Enumerable. Эти методы предназначены главным образом для поддержки LINQ, хотя их можно применять и в других целях. Интерфейс IList В интерфейсе IList объявляется такое поведение необобщенной коллекции, которое позволяет осуществлять доступ к ее элементам по индексу с отсчетом от нуля. Этот интерфейс наследует от интерфейсов ICollection и IEnumerable. Помимо методов, определенных в этих интерфейсах, в интерфейсе IList определяется ряд собственных методов. Все эти методы сведены в табл. 25.2. В некоторых из них предусматривается модификация коллекции. Если же коллекция доступна только для чтения или имеет фиксированный размер, то в этих методах генерируется исключение NotSupportedException. Tafuuiia 9fv9_ Мртплы пппрлрлрнныр r интрпгЬрйпр TLisI‑ Метод Описание int Add(object value) void Clear () bool Contains(object value) Добавляет объект value в вызывающую коллекцию. Возвращает индекс, по которому этот объект сохраняется Удаляет все элементы из вызывающей коллекции Возвращает логическое значение true, если вызывающая коллекция содержит объект value , а иначе – логическое значение false Метод Описание int IndexOf(object value) void Insert (int index, object value) void Remove(object value) void RemoveAt(int index) Возвращает индекс объекта value, если этот объект содержится в вызывающей коллекции. Если же объект value не обнаружен, то метод возвращает значение ‑1 Вставляет в вызывающую коллекцию объект value по индексу index. Элементы, находившиеся до этого по индексу index и дальше, смещаются вперед, чтобы освободить место для вставляемого объекта value Удаляет первое вхождение объекта value в вызывающей коллекции. Элементы, находившиеся до этого за удаленным элементом, смещаются назад, чтобы устранить образовавшийся “пробел” Удаляет из вызывающей коллекции объект, расположенный по указанному индексу index. Элементы, находившиеся до этого за удаленным элементом, смещаются назад, чтобы устранить образовавшийся “пробел” Объекты добавляются в коллекцию типа IList вызовом метода Add (). Обратите внимание на то, что метод Add () принимает аргумент типа obj ect. А поскольку 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 (). Как только элемент будет добавлен в коллекцию, он станет доступным посредством индексатора. Интерфейс IDictionary В интерфейсе IDictionary определяется такое поведение необобщенной коллекции, которое позволяет преобразовать уникальные ключи в соответствующие значения. Ключ представляет собой объект, с помощью которого значение извлекается впоследствии. Следовательно, в коллекции, реализующей интерфейс IDictionary, хранятся пары "ключ‑значение". Как только подобная пара будет сохранена, ее можно извлечь с помощью ключа. Интерфейс IDictionary наследует от интерфейсов ICollection и IEnumerable. Методы, объявленные в интерфейсе IDictionary, сведены в табл. 25.3. Некоторые из них генерируют исключение ArgumentNullException при попытке указать пустой ключ, поскольку пустые ключи не допускаются. Таблица 25.3. Методы, определенные в интерфейсе IDictionary Метод Описание |