Перерахування можна використовувати для зберігання бітових флагів, завдяки цьому екземпляр 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.