Этот класс не определяет никакого порядка для добавления или извлечения элементов. Он реализует концепцию отображения потоков на используемые внутренне массивы, и старается избежать блокировок. Для доступа к элементам применяются методы Add(), TryPeek() и TryTake(). [2]<TKey, TValue>
Безопасная в отношении потоков коллекция ключей и значений. Для доступа к членам в неблокирующем режиме служат методы TryAdd(), TryGetValue(), TryRemove() и TryUpdate(). Поскольку элементы основаны на ключах и значениях, ConcurrentDictionary<TKey, TValue> не реализует интерфейс IProducerConsumerCollection<T>. [2]. Эти коллекции безопасны к потокам в том смысле, что возвращают false, если какое-то действие над ними невозможно при текущем состоянии потоков. Прежде чем предпринимать какие-то дальнейшие действия, всегда следует проверять успешность добавления или извлечения элементов. Полностью доверять коллекции решение задачи нельзя. [2]<T>
Коллекция, которая осуществляет блокировку и ожидает, пока не появится возможность выполнить действие по добавлению или извлечению элемента. BlockingCollection<T> предлагает интерфейс для добавления и извлечения элементов методами Add() и Take(). Эти методы блокируют поток и затем ожидают, пока не появится возможность выполнить задачу. [2]
Метод Add() имеет перегрузку, которой можно также передать CancellationToken. Эта лексема всегда отменяет блокирующий вызов. Если не нужно, чтобы поток ожидал бесконечное время, без отмены вызова, доступны также методы TryAdd() и TryTake(). В них можно указать значение таймаута - максимального периода времени, в течение которого вы готовы блокировать поток и ждать, пока вызов не даст сбой. [2]
. Специальные и наблюдаемые коллекции
.1 Специальные коллекции
В среде .NET Framework предусмотрен ряд специальных коллекций,
оптимизированных для работы с данными конкретного типа или для их обработки
особым образом. Классы этих необобщенных коллекций определены в пространстве
имен System.Collections.Specialized и перечислены в таблице 5. [3]
Таблица 5 - Специальные коллекции C#
|
Класс специальной коллекции |
Описание |
|
CollectionsUtil |
Содержит фабричные методы для создания коллекций |
|
HybridDictionary |
Предназначен для коллекций, в которых для хранения небольшого количества пар "ключ-значение" используется класс ListDictionary. При превышении коллекцией определенного размера автоматически используется класс Hashtable для хранения ее элементов |
|
ListDictionary |
Предназначен для коллекций, в которых для хранения пар "ключ-значение" используется связный список. Такие коллекции рекомендуются только для хранения небольшого количества элементов |
|
NameValueCollection |
Предназначен для отсортированных коллекций, в которых хранятся пары "ключ-значение", причем и ключ, и значение относятся к типу string |
|
OrderedDictionary |
Предназначен для коллекций, в которых хранятся индексируемые пары "ключ-значение" |
|
StringCollection |
Предназначен для коллекций, оптимизированных для хранения символьных строк |
|
StringDictionary |
Предназначен для хеш-таблиц, в которых хранятся пары "ключ-значение", причем и ключ, и значение относятся к типу string |
Кроме того, в пространстве имен System.Collections определены три базовых абстрактных класса: CollectionBase, ReadOnlyCollectionBase и DictionaryBase. Эти классы могут наследоваться и служить в качестве отправной точки для разработки собственных специальных коллекций. [2]
5.2 Наблюдаемые коллекции
В случае если нужна информация о том, когда элементы коллекции удаляются или добавляются, можно использовать класс ObservableCollection<T>. Этот класс был определен для WPF и предназначен для того, чтобы пользовательский интерфейс мог получать информацию об изменениях коллекции. По этой причине он включен в сборку WindowsBase, следовательно, на нее необходимо сослаться. Пространство имен этого класса - System.Collections.ObjectModel. [2]
Класс ObservableCollection<T> унаследован от базового класса Collection<T>, который может применяться для создания специальных коллекций; он использует внутри себя List<T>. Методы базового класса SetItem() и RemoveItem() переопределены для инициации события CollectionChanged. Клиенты этого класса могут регистрироваться на это событие, используя интерфейс INotifyCollectionChanged.
В следующем примере показано применение ObservableCollection<string>, при этом метод Data_CollectionChanged регистрируется на событие CollectionChanged.
Два элемента добавляются в конец коллекции, затем еще один вставляется и один удаляется:
data = new ObservableCollection<string>();.CollectionChanged += Data_CollectionChanged;.Add("One");.Add("Two");.Insert(1, "Three");
data.Remove("One");
Метод Data_CollectionChanged принимает аргумент NotifyCollection Changed EventArgs, содержащий информацию об изменениях коллекции.
Свойство Action предоставляет информацию о том, был элемент добавлен или удален. Для удаленных элементов устанавливается свойство OldItems, перечисляющее удаленные элементы.
При добавлении элементов устанавливается свойство NewItems, которое
перечисляет новые элементы.
. Битовые коллекции
Если требуется иметь дело с множеством битов, можно применить класс
BitArray и структуру BitVector32. Класс BitArray расположен в пространстве имен
System.Collections, a BitVector32 - в пространстве
System.Collections.Specialized. Наиболее важное отличие между этими двумя
типами состоит в том, что BitArray имеет изменяемый размер, а это удобно, когда
необходимое количество бит известно заранее, и оно велико. Структура
BitVector32 основана на стеке, и потому работает быстрее. BitVector32 содержит
только 32 бита, которые хранятся в целом числе. [3]
.1 Класс BitArray
Класс BitArray служит для хранения отдельных битов в коллекции. А поскольку в коллекции этого класса хранятся биты, а не объекты, то своими возможностями он отличается от классов других коллекций. Тем не менее, в классе BitArray реализуются интерфейсы ICollection и IEnumerable как основополагающие элементы поддержки всех типов коллекций. Кроме того, в классе BitArray реализуется интерфейс ICloneable. [2]
В классе BitArray определено несколько конструкторов. Так, с помощью приведенного ниже конструктора можно сконструировать объект типа BitArray из массива логических значений:
BitArray(bool[] values)
В данном случае каждый элемент массива values становится отдельным битом в коллекции. Это означает, что каждому элементу массива values соответствует отдельный бит в коллекции. Более того, порядок расположения элементов в массиве values сохраняется и в коллекции соответствующих им битов. Коллекцию типа BitArray можно также составить из массива байтов, используя следующий конструктор: [2]
BitArray(byte[] bytes)
Здесь битами в коллекции становится уже целый их набор из массива bytes, причем элемент bytes [0] обозначает первые 8 битов, элемент bytes [1] вторые 8 битов и т.д. [2]
Коллекции типа BitArray подлежат индексированию. По каждому индексу указывается отдельный бит в коллекции, причем нулевой индекс обозначает младший бит.
В классе BitArray определяется ряд собственных методов, помимо тех, что уже объявлены в интерфейсах, которые в нем реализуются. Методы этого класса приведены ниже. [3]
В классе BitArray не поддерживается метод Synchronized(). Это означает, что для коллекций данного класса синхронизированная оболочка недоступна, а свойство IsSynchronized всегда имеет логическое значение false. Тем не менее, для управления доступом к коллекции типа BitArray ее можно синхронизировать для объекта, предоставляемого в упоминавшемся ранее свойством SyncRoot. [2]()
Выполняет операцию логического умножения (И) битов вызывающего объекта и коллекции value. Возвращает коллекцию типа BitArray, содержащую результат()
Возвращает значение бита, указываемого по индексу()
Выполняет операцию поразрядного логического отрицания (НЕ) битов вызывающей коллекции и возвращает коллекцию типа BitArray, содержащую результат()
Выполняет операцию логического сложения (ИЛИ) битов вызывающего объекта и коллекции value. Возвращает коллекцию типа BitArray, содержащую результат. [2]()
Устанавливает бит, указываемый по индексу index, равным значению value()
Устанавливает все биты равными значению value()
Выполняет логическую операцию исключающее (ИЛИ) над битами вызывающего объекта и коллекции value. Возвращает коллекцию типа BitArray, содержащую результат. [2]
В классе BitArray определяется также собственное свойство, помимо тех, что указаны в интерфейсах, которые в нем реализуются:
int Length { get; set; }
Свойство Length позволяет установить или получить количество битов в
коллекции. Следовательно, оно возвращает такое же значение, как и стандартное
свойство Count, определяемое для всех коллекций. В отличие от свойства Count,
свойство Length доступно не только для чтения, но и для записи, а значит, с его
помощью можно изменить размер коллекции типа BitArray. [3]
.2 Структура BitVector
Если необходимое количество бит известно заранее, то вместо BitArray можно использовать структуру BitVector32. Структура BitVector32 более эффективна, поскольку это тип значения, хранящий биты в стеке внутри целого числа. В единственном целом числе имеется место для 32 бит.
Если нужно больше, можно применять множество значений BitVector32 или же BitArray. Класс BitArray при необходимости может расти, а структура BitVector32 лишена такой возможности. [2]
Ниже перечислены члены структуры BitVector32, которые существенно отличаются от BitArray:
Свойство Data возвращает данные BitVector32 в виде целого числа.
Значение BitVector32 может быть установлено с использованием целого числа. Индексатор перегружен: получать и устанавливать значения можно с использованием маски или секции типа BitVector32.Section.()
Статический метод, который позволяет создавать маску для доступа к определенным битам Bitvector32.()
Статический метод, который позволяет создавать несколько секций внутри 32 бит. В приведенном ниже примере создается структура BitVector32 с помощью конструктора по умолчанию, при этом все 32 бита инициализируются false. Затем создаются маски для доступа к битам внутри битового вектора. Первый вызов CreateMask() создает маску для доступа к первому биту. После вызова CreateMask() значение bitl равно 1. [2]
Еще один вызов CreateMask() возвращает маску для доступа ко второму биту,
которая равна 2.bit3 имеет значение 4 для доступа к биту номер 3. bit4 имеет
значение 8 для доступа к биту номер 4.Затем маски используются с индексатором
для доступа к битам внутри вектора бит и соответствующей установки полей:
var bitsl = new BitVector32 () ;bitl =
BitVector32.CreateMask();bit2 = BitVector32.CreateMask(bitl);bit3 =
BitVector32.CreateMask(bit2);bit4 = BitVector32.CreateMask(bit3);bit5 =
BitVector32.CreateMask(bit4);[bitl] = true;[bit2] = false;[bit3] = true;[bit4]
= true;[bi15] = true;.WriteLine(bits1);
7. Реализация интерфейса
IComparable
Если требуется отсортировать коллекцию, состоящую из объектов определяемого пользователем класса, при условии, что они не сохраняются в коллекции класса SortedList, где элементы располагаются в отсортированном порядке, то в такой коллекции должен быть известен способ сортировки содержащихся в ней объектов. С этой целью можно, в частности, реализовать интерфейс IComparable для объектов сохраняемого типа. Интерфейс IComparable доступен в двух формах: обобщенной и необобщенной. Несмотря на сходство применения обеих форм данного интерфейса, между ними имеются некоторые, хотя и небольшие, отличия. [2]
Если требуется отсортировать объекты, хранящиеся в необобщенной коллекции, то для этой цели придется реализовать необобщенный вариант интерфейса IComparable. В этом варианте данного интерфейса определяется только один метод, CompareTo(), который определяет порядок выполнения самого сравнения. Ниже приведена общая форма объявления метода CompareTo():
CompareTo(object obj)
В методе CompareTo() вызывающий объект сравнивается с объектом obj. Для сортировки объектов по нарастающей конкретная реализация данного метода должна возвращать нулевое значение, если значения сравниваемых объектов равны; положительное - если значение вызывающего объекта больше, чем у объекта obj; и отрицательное - если значение вызывающего объекта меньше, чем у объекта obj. А для сортировки по убывающей можно обратить результат сравнения объектов. Если же тип объекта obj не подходит для сравнения с вызывающим объектом, то в методе CompareTo() может быть сгенерировано исключение ArgumentException. [2]
Если требуется отсортировать объекты, хранящиеся в обобщенной коллекции, то для этой цели придется реализовать обобщенный вариант интерфейса IComparable<T>. В этом варианте интерфейса IComparable определяется приведенная ниже обобщенная форма метода CompareTo():
CompareTo(Т other). [2]
В методе CompareTo() вызывающий объект сравнивается с другим объектом other.
Для сортировки объектов по нарастающей конкретная реализация данного
метода должна возвращать нулевое значение, если значения сравниваемых объектов
равны; положительное - если значение вызывающего объекта больше, чем у объекта
другого other; и отрицательное если значение вызывающего объекта меньше, чем у
другого объекта other. А для сортировки по убывающей можно обратить результат
сравнения объектов. При реализации обобщенного интерфейса IComparable<T>
имя типа реализующего класса обычно передается в качестве аргумента типа. [2]
8. Реализация интерфейса IComparer
Для сортировки объектов определяемых пользователем классов зачастую проще всего реализовать в этих классах интерфейс IComparable. Тем не менее, данную задачу можно решить и с помощью интерфейса IComparer. Для этой цели необходимо сначала создать класс, реализующий интерфейс IComparer, а затем указать объект этого класса, когда потребуется сравнение. [2]
Интерфейс IComparer существует в двух формах: обобщенной и необобщенной. Несмотря на сходство применения обеих форм данного интерфейса, между ними имеются некоторые, хотя и небольшие, отличия.
В необобщенном интерфейсе IComparer определяется только один метод Compare():
Compare(object x, object у)
В методе Compare() сравниваются объекты х и у. Для сортировки объектов по нарастающей конкретная реализация данного метода должна возвращать нулевое значение, если значения сравниваемых объектов равны; положительное - если значение объекта х больше, чем у объекта у; и отрицательное - если значение объекта х меньше, чем у объекта у. А для сортировки по убывающей можно обратить результат сравнения объектов. Если же тип объекта х не подходит для сравнения с объектом у, то в методе CompareTo() может быть сгенерировано исключение ArgumentException. [2]
Объект типа IComparer может быть указан при конструировании объекта класса SortedList, при вызове метода ArrayList.Sort(IComparer), а также в ряде других мест в классах коллекций. Главное преимущество применения интерфейса IComparer заключается в том, что сортировке подлежат объекты тех классов, в которых интерфейс IComparable не реализуется. [2]
Интерфейс IComparer<T> является обобщенным вариантом интерфейса IComparer. В нем определяется приведенный ниже обобщенный вариант метода Compare():
Compare(Т х, T у)
В этом методе сравниваются объекты х и у и возвращается нулевое значение,
если значения сравниваемых объектов равны; положительное - если значение
объекта х больше, чем у объекта у; и отрицательное - если значение объекта х
меньше, чем у объекта у. [2]
9. Перечислители
К элементам коллекции нередко приходится обращаться циклически, например, для отображения каждого элемента коллекции. С этой целью можно, с одной стороны, организовать цикл foreach, а с другой - воспользоваться перечислителем. Перечислитель - это объект, который реализует необобщенный интерфейс IEnumerator или обобщенный интерфейс IEnumerator<T>. [2]
В интерфейсе IEnumerator определяется одно свойство, Current, необобщенная форма которого приведена ниже:
Current {get;}
А в интерфейсе IEnumerator<T> объявляется следующая обобщенная
форма свойства Current:
Т Current {get;}
В обеих формах свойства Current получается текущий перечисляемый элемент коллекции. Но поскольку свойство Current доступно только для чтения, то перечислитель может служить только для извлечения, но не видоизменения объектов в коллекции. [2]
В интерфейсе IEnumerator определяются два метода. Первым из них является метод MoveNext(), объявляемый следующим образом:
MoveNext()
При каждом вызове метода MoveNext() текущее положение перечислителя смещается к следующему элементу коллекции. Этот метод возвращает логическое значение true, если следующий элемент коллекции доступен, и логическое значение false, если достигнут конец коллекции. Перед первым вызовом метода MoveNext() значение свойства Current оказывается неопределенным. [2]