Перерахування як бітові флажки

Перерахування можна використовувати для зберігання бітових флагів, завдяки цьому екземпляр enum може зберігати в собі комбінацію значень констант, визначених в списку. Для створення перерахування з бітовими флажками, використовується атрибут [Flags]. Значення констант задаються таким чином, щоб до них можна було застосовувати бітові операції.

Для використання перерахувань як бітових флажків необхідно виконувати наступні правила:

  • Обов’язково включайте в перерахування константу зі значенням 0, зазвичай використовується ім’я None;
  • Константи повинні бути степенями двійки 1, 2, 4… Це гарантує, що комбінація флагів не будуть перекриватися;
  • Якщо поєднання флажків часто використовується, добавте їх в перерахування;
  • Для констант використовуйте тільки додатні значення, оскільки від’ємні можуть внести неоднозначність.

Визначення бітових флагів перерахувань

Оскільки константи повинні містити ступені двійки, можна задавати їх декількома варіантами:

  • Двійковими літералами;
  • Числовим літералом з операцією зсуву;
  • Числами десяткової системи;
  • Літералами шістнадцяткової системи.

Для присвоєння значень констант, простіше і наочніше використовувати двійкові літерали:

[Flags]
enum AccessType
{
    Deny      = 0b00,
    ReadOnly  = 0b01,
    Write     = 0b10,
    ReadWrite = 0b11 //часто використовуване поєднання флажків
}

або операцію зсуву:

[Flags]
enum Border
{
    None   = 0,
    Left   = 1 << 0, //1
    Top    = 1 << 1, //2
    Right  = 1 << 2, //4
    Bottom = 1 << 3  //8
}

Бітові операції

Для комбінування, скидання та перевірки флажків використовуються бітові операції.

Розглянемо приклад перерахування яке описує дні тижня, значення запишемо у вигляді двійкових літералів(можна використовувати будь яку з доступних систем числення). За допомогою бітових операцій ми можемо ввести змінні, які позначають вихідні та робочі дні тижня.

using System;
class Program
{
    [Flags]
    enum Days
    {
        Not = 0b00000000,
        Mon = 0b00000001,
        Tue = 0b00000010,
        Wed = 0b00000100,
        Thu = 0b00001000,
        Fri = 0b00010000,
        Sat = 0b00100000,
        Sun = 0b01000000,
        //флажки можна комбінувати створюючи набори за допомогою констант
        WorkingDays = Mon | Tue | Wed | Thu | Fri, //0b00011111
        //або використовуючи значення
        Weekend = 0b01100000 //Sat|Sun
    }


    static void Main(string[] args)
    {
        var monday = Days.Mon;
        //перевірка бітового флажка
        if ((monday & Days.WorkingDays) != 0)
        {
            Console.WriteLine("Понеділок - робочий день");
        }

        var goodDays = Days.Thu | Days.Tue;
        var badDays = Days.Fri | Days.Mon;
        Console.WriteLine($"Хороші дні: {goodDays}");
        Console.WriteLine($"Погані дні: {badDays}");
        Console.ReadLine();
    }
}

Як можна побачити в прикладі, для встановлення флажка використовується оператор |(бітове або):

var x = Days.Mon | Days.Tue;
x |= Days.Fri;
Console.WriteLine(x);

Для перевірки флажка використовується конструкція з оператором &(побітове і):

bool flag1 = (x & Days.Fri) == Days.Fri; //true
//або
bool flag2 = (x & Days.Fri) != 0; //true

Для скидання флажка можна використовувати оператор ^(xor):

x = x ^ Days.Tue;
Console.WriteLine(x);

Бітові маски часто використовуються в середовищі .Net, зокрема для створення прив’язки об’єктів до контейнерів(Anchor) та визначення рівня доступу до файлів(FileAccess), це тільки мала частина з перерахувань, які входять до складу .Net Framework.

Дивіться також: