C# Enum и Атрибут Flags

Возникают ситуации, когда переменная должна хранить несколько значений типа перечисления. Например, используемые области логирования: Warning + Info, или сочетания цветов: Red + Blue + Green.

Для хранения в переменной нескольких флагов, значениям енама присваиваются степени двойки:

[Flags]
public enum MyColors
{
    Yellow = 1,
    Green = 2,
    Red = 4,
    Blue = 8
}

Значения 2, 4, 8 используются для операторов смещения, таких как побитовое И (AND), ИЛИ (OR) и исключающее ИЛИ (XOR).

Операции над переменной

Логическое ИЛИ (|) применяется для помещения нескольких значений флагов в одну переменную:

myProperties.AllowedColors = MyColor.Red | MyColor.Green | MyColor.Blue;

Логическое И (&) помогает при нахождении значения флага:

if((myProperties.AllowedColors & MyColor.Yellow) == MyColor.Yellow)
{
    // Yellow has been set...
}

if((myProperties.AllowedColors & MyColor.Green) == MyColor.Green)
{
    // Green has been set...
}

Начиная с .Net 4 можно использовать сокращенную версию, без явного указания &:

if (myProperties.AllowedColors.HasFlag(MyColor.Yellow))
{
    // Yellow has been set...
}

Операция XOR (’^’) исключает значения из переменной:

myProperties.AllowedColors = MyColor.Red | MyColor.Green | MyColor.Blue;
// Удаляем значение используя оператор смещения XOR.
myProperties.AllowedColors = myProperties.AllowedColors ^ MyColor.Green;
Console.WriteLine("My colors are {0}", myProperties.AllowedColors);
// Output: My colors are Red, Blue

Атрибут Flags

Атрибут [Flags] необязательный и используется для красивого вывода при вызове .ToString():

enum Colors { Yellow = 1, Green = 2, Red = 4, Blue = 8 }
[Flags] enum ColorsFlags { Yellow = 1, Green = 2, Red = 4, Blue = 8 }
...
var str1 = (Colors.Yellow | Colors.Red).ToString(); // "5"
var str2 = (ColorsFlags.Yellow | ColorsFlags.Red).ToString(); // "Yellow, Red"

Так же, атрибут [Flags] не присваивает значениям степень двойки. Если не проставить вручную, то значения инициализируются как в обычном енаме.

Неправильное объявление:

[Flags]
public enum MyColors
{
    Yellow,
    Green,
    Red,
    Blue
}

Присвоенные значения: Yellow = 0, Green = 1, Red = 2, Blue = 3. Они не подходят для использования операций смещения.

Битовое представление

Описанное выше работает благодаря битовому представлению значений флагов при проставлении степени двойки:

Yellow: 00000001
Green:  00000010
Red:    00000100
Blue:   00001000

Значение переменной AllowedColors после присваивания Red, Green и Blue c использованием операции ИЛИ (|):

myProperties.AllowedColors: 00001110

Теперь, для проверки вхождения значения Green в переменную используем операцию смещения И (&):

myProperties.AllowedColors: 00001110
             MyColor.Green: 00000010
             -----------------------
                            00000010 // Это то же самое, что и MyColor.Green!

Полезные ссылки

Плюсануть
Поделиться
Отправить
2015   dotnet  
← Почему стоит использовать zsh вместо bash  
Как тестировать абстрактные классы →

comments powered by Disqus