День сорок третий. #ЗаметкиНаПолях

Битовые флаги

Тип перечисления можно использовать для определения битовых флагов, благодаря чему экземпляр типа перечисления может хранить любую комбинацию значений, определенных в списке перечислителя.

Чтобы создать перечисление битовых флагов, нужно:

1. Добавить атрибут System.FlagsAttribute.

2. Определить значения так, чтобы для них могли выполняться битовые операции AND, OR, NOT и XOR.

3. Добавить именованную константу с нулевым значением, что означает "флаги не установлены" (не задавайте флагу нулевое значение, если оно не означает "флаги не установлены").

В следующем примере у перечисления Days имеется атрибут Flags, и каждому значению присваивается следующая степень числа 2:

[Flags]

enum Days

{

None = 0x0,

Sunday = 0x1,

Monday = 0x2,

Tuesday = 0x4,

Wednesday = 0x8,

Thursday = 0x10,

Friday = 0x20,

Saturday = 0x40

}

Чтобы установить несколько флагов перечисления, используйте битовый оператор OR:

// Устанавливаем два флага с помощью битового OR

meetingDays = Days.Tuesday | Days.Thursday;



// Добавляем флаг с помощью битового OR

meetingDays = meetingDays | Days.Friday;



Console.WriteLine("Дни встречи: {0}", meetingDays);

// Вывод: Дни встречи: Tuesday, Thursday, Friday



// Снимаем флаг с помощью битового XOR

meetingDays = meetingDays ^ Days.Tuesday;

Console.WriteLine("Дни встречи: {0}", meetingDays);

// Вывод: Дни встречи: Thursday, Friday



Чтобы определить, установлен ли конкретный флаг, используйте битовый оператор AND:

// Проверка, установлен ли флаг с помощью битового AND

bool test = (meetingDays & Days.Thursday) == Days.Thursday;

Console.WriteLine("Thursday – это {0}день встречи.", test == true ? "" : "не ");

// Вывод: Thursday – это день встречи.



Кроме того, можно получить числовое значение строки, содержащей разделённые запятыми идентификаторы флагов, с помощью методов Parse или TryParse типа Enum:

Days d = (Days)Enum.Parse(typeof(Days), "monday,sunday", true);

Console.WriteLine("Дни встречи: {0}", d);

// Вывод: Дни встречи: Sunday, Monday



if (Enum.TryParse("friday,sunday", true, out d))

Console.WriteLine("Дни встречи: {0}", d);

// Вывод: Дни встречи: Sunday, Monday

При этом:

- значения могут быть неупорядоченными, метод Parse упорядочивает их;

- параметр ignoreCase позволяет игнорировать регистр символов;

- метод TryParse на самом деле обобщённый (TryParse<Days>), но параметр типа можно не указывать, он определяется по типу последнего out параметра.



Также для парсинга можно использовать числовое значение (сумму числовых значений флагов):

if (Enum.TryParse("108", true, out d))

Console.WriteLine("Дни встречи: {0}", d);

// Вывод: Дни встречи: Tuesday, Wednesday, Friday, Saturday



Источники:

- Джеффри Рихтер “CLR via C#”. 3-е изд. – СПб.: Питер, 2012. Глава 15.

-
https://docs.microsoft.com/ru-ru/dotnet/csharp/programming-guide/enumeration-types