Битовые коллекции
Если требуется иметь дело с множеством битов, можно применить класс BitArray и структуру BitVector32. Класс BitArray расположен в пространстве имен System.Collections, a BitVector32 — в пространстве System.Collections.Specialized. Наиболее важное отличие между этими двумя типами состоит в том, что BitArray имеет изменяемый размер, а это удобно, когда необходимое количество бит известно заранее, и оно велико. Структура BitVector32 основана на стеке, и потому работает быстрее. BitVector32 содержит только 32 бита, которые хранятся в целом числе.
Класс 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 подлежат индексированию. По каждому индексу указывается отдельный бит в коллекции, причем нулевой индекс обозначает младший бит.
В классе BitArray определяется ряд собственных методов, помимо тех, что уже объявлены в интерфейсах, которые в нем реализуются. Методы этого класса приведены ниже. Обратите внимание на то, что в классе BitArray не поддерживается метод Synchronized(). Это означает, что для коллекций данного класса синхронизированная оболочка недоступна, а свойство IsSynchronized всегда имеет логическое значение false. Тем не менее для управления доступом к коллекции типа BitArray ее можно синхронизировать для объекта, предоставляемого упоминавшимся ранее свойством SyncRoot.
- And()
-
Выполняет операцию логического умножения (И) битов вызывающего объекта и коллекции value. Возвращает коллекцию типа BitArray, содержащую результат
- Get()
-
Возвращает значение бита, указываемого по индексу
- Not()
-
Выполняет операцию поразрядного логического отрицания (НЕ) битов вызывающей коллекции и возвращает коллекцию типа BitArray, содержащую результат
- Or()
-
Выполняет операцию логического сложения (ИЛИ) битов вызывающего объекта и коллекции value. Возвращает коллекцию типа BitArray, содержащую результат
- Set()
-
Устанавливает бит, указываемый по индексу index, равным значению value
- SetAll()
-
Устанавливает все биты равными значению value
- Xor()
-
Выполняет логическую операцию исключающее (ИЛИ) над битами вызывающего объекта и коллекции value. Возвращает коллекцию типа BitArray, содержащую результат
В классе BitArray определяется также собственное свойство, помимо тех, что указаны в интерфейсах, которые в нем реализуются:
public int Length { get; set; }
Свойство Length позволяет установить или получить количество битов в коллекции. Следовательно, оно возвращает такое же значение, как и стандартное свойство Count, определяемое для всех коллекций. В отличие от свойства Count, свойство Length доступно не только для чтения, но и для записи, а значит, с его помощью можно изменить размер коллекции типа BitArray.
Давайте рассмотрим пример использования класса BitArray:
using System; using System.Collections; namespace ConsoleApplication1 { class Program { static void WriteBits(BitArray bits) { foreach (bool b in bits) Console.Write(b ? 1 : 0); Console.WriteLine("\n"); } static void Main() { BitArray bits1 = new BitArray(10); BitArray bits2 = new BitArray(10); bits1.SetAll(false); bits1.Set(2, true); bits1[3] = true; bits1[8] = true; bits2 = bits1; bits1 = bits1.Not(); Console.Write("bits1: "); WriteBits(bits1); Console.Write("bits2: "); WriteBits(bits2); Console.Write("NOT(bits1): "); bits1.Not(); WriteBits(bits1); Console.Write("bits1 AND bits2: "); bits1.And(bits2); WriteBits(bits1); Console.ReadLine(); } } }
Структура BitVector32
Если необходимое количество бит известно заранее, то вместо BitArray можно использовать структуру BitVector32. Структура BitVector32 более эффективна, поскольку это тип значения, хранящий биты в стеке внутри целого числа. В единственном целом числе имеется место для 32 бит. Если нужно больше, можно применять множество значений BitVector32 или же BitArray. Класс BitArray при необходимости может расти, а структура BitVector32 лишена такой возможности.
Ниже перечислены члены структуры BitVector32, которые существенно отличаются от BitArray:
- Data
-
Свойство Data возвращает данные BitVector32 в виде целого числа.
- Item
-
Значение BitVector32 может быть установлено с использованием целого числа. Индексатор перегружен: получать и устанавливать значения можно с использованием маски или секции типа BitVector32.Section.
- CreateMask()
-
Статический метод, который позволяет создавать маску для доступа к определенным битам Bitvector32.
- CreateSelection()
-
Статический метод, который позволяет создавать несколько секций внутри 32 бит.
В приведенном ниже примере создается структура BitVector32 с помощью конструктора по умолчанию, при этом все 32 бита инициализируются false. Затем создаются маски для доступа к битам внутри битового вектора. Первый вызов CreateMask() создает маску для доступа к первому биту. После вызова CreateMask() значение bitl равно 1. Еще один вызов CreateMask() возвращает маску для доступа ко второму биту, которая равна 2. bit3 имеет значение 4 для доступа к биту номер 3. bit4 имеет значение 8 для доступа к биту номер 4.
Затем маски используются с индексатором для доступа к битам внутри вектора бит и соответствующей установки полей:
var bitsl = new BitVector32 () ; int bitl = BitVector32.CreateMask(); int bit2 = BitVector32.CreateMask(bitl); int bit3 = BitVector32.CreateMask(bit2); int bit4 = BitVector32.CreateMask(bit3); int bit5 = BitVector32.CreateMask(bit4); bitsl[bitl] = true; bitsl[bit2] = false; bitsl[bit3] = true; bitsl[bit4] = true; bitsl[bi15] = true; Console.WriteLine(bits1);
Комментарии