C# типы перечислений — использование флагов

Типы перечислений с C# представляют эффективный способ определения набора именованных целочисленных констант. В большинстве случаев перечисления используются для хранения/получения одного определённого значения. Но типы перечислений можно использовать для определения битовых флагов, благодаря чему экземпляр типа будет способен хранить любую комбинацию определённых значений.
Допустим, в нашей программе необходимо задать день недели, в который произойдёт определённое событие. Для хранения дней недели определим перечисления (Enum):

 
public enum Days
    {
        Sunday = 7,
        Monday = 1,
        Tuesday = 2,
        Wednesday = 3,
        Thursday = 4,
        Friday = 5,
        Saturday = 6
    }

Теперь, чтобы задать определённый день недели достаточно написать var day = Days.Friday; Но в таком виде, в переменную day можно записать значения только одного дня, а если возникнет необходимость задать значения нескольких дней возникнет проблема.
Для её решения существуют флаги. Перечисления битовых флагов задаётся атрибутом System.FlagsAttribute ([Flags]), также для задания целочисленных значений следует использовать степени двойки.
То есть необходимо только добавить [Flags] к перечислению, после этого станут доступны битовые операции AND, OR, NOT и XOR:

 
    [Flags]
    public enum Days
    {
        Sunday = 64,
        Monday = 1,
        Tuesday = 2,
        Wednesday = 4,
        Thursday = 8,
        Friday = 16,
        Saturday = 32
    }

Значения нескольких дней можно задать используя побитовый оператор OR следующим образом:

 
var day = Days.Monday | Days.Wednesday | Days.Friday;
Console.WriteLine(day);

Выведется строка: Monday, Wednesday, Friday Чтобы проверить, установлен ли определённый флаг, следует воспользоваться побитовым AND.

  
var day = Days.Monday | Days.Wednesday | Days.Friday;
Console.WriteLine((day & Days.Friday) == Days.Friday); //True
Console.WriteLine((day & Days.Sunday) == Days.Sunday); //False

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

 
var strDays = "Monday, Wednesday, Thursday";
Days days;
bool success = Enum.TryParse<Days>(strDays, out days);
if (success)
{
    Console.WriteLine(days);
}

Если возникнет необходимость циклически просмотреть все имеющиеся значения в перечислении, либо их имена, можно сделать следующее:

 
foreach (int i in Enum.GetValues(typeof(Days)))
    Console.WriteLine(i);
foreach (string i in Enum.GetNames(typeof(Days)))
    Console.WriteLine(i);

Получив на выходе:

Комментарии (3) -

А что будет, если не задать атрибут [Flags]? На что это влияет? Что перестанет работать, а что нет?

Сергей 11.04.2018 5:34:36

Мне кажется ошибочка в строчке:
Console.WriteLine((day & Days.Friday) == Days.Sunday); //False
Думаю должно быть так:
Console.WriteLine((day & Days.Sunday) == Days.Sunday); //False

Андрей 11.04.2018 21:48:17

Вы правы, там была ошибка. Поправил это, спасибо.

Добавить комментарий