[Flags]
Атрибут должен быть использован всякий раз , когда перечислимы представляет собой набор возможных значений, а не одно значение. Такие коллекции часто используются с побитовыми операторами, например:
var allowedColors = MyColor.Red | MyColor.Green | MyColor.Blue;
Обратите внимание, что [Flags]
атрибут не включает это сам по себе - все, что он делает, это разрешает хорошее представление .ToString()
методом:
enum Suits { Spades = 1, Clubs = 2, Diamonds = 4, Hearts = 8 }
[Flags] enum SuitsFlags { Spades = 1, Clubs = 2, Diamonds = 4, Hearts = 8 }
...
var str1 = (Suits.Spades | Suits.Diamonds).ToString();
// "5"
var str2 = (SuitsFlags.Spades | SuitsFlags.Diamonds).ToString();
// "Spades, Diamonds"
Также важно отметить, что перечислимые значения автоматически [Flags]
не делаются равными двум. Если вы опустите числовые значения, перечисление не будет работать так, как можно ожидать в побитовых операциях, потому что по умолчанию значения начинаются с 0 и увеличиваются.
Неверная декларация:
[Flags]
public enum MyColors
{
Yellow, // 0
Green, // 1
Red, // 2
Blue // 3
}
Значения, если они объявлены таким образом, будут Yellow = 0, Green = 1, Red = 2, Blue = 3. Это сделает его бесполезным в качестве флагов.
Вот пример правильного объявления:
[Flags]
public enum MyColors
{
Yellow = 1,
Green = 2,
Red = 4,
Blue = 8
}
Чтобы получить различные значения в вашей собственности, можно сделать это:
if (myProperties.AllowedColors.HasFlag(MyColor.Yellow))
{
// Yellow is allowed...
}
или до .NET 4:
if((myProperties.AllowedColors & MyColor.Yellow) == MyColor.Yellow)
{
// Yellow is allowed...
}
if((myProperties.AllowedColors & MyColor.Green) == MyColor.Green)
{
// Green is allowed...
}
Под одеялом
Это работает, потому что вы использовали степени двух в своем перечислении. Под крышками ваши значения перечисления выглядят следующим образом в двоичных единицах и нулях:
Yellow: 00000001
Green: 00000010
Red: 00000100
Blue: 00001000
Точно так же, после того как вы установили для свойства AllowedColors значение Red, Green и Blue с помощью двоичного побитового |
оператора OR , AllowedColors выглядит следующим образом:
myProperties.AllowedColors: 00001110
Поэтому, когда вы извлекаете значение, вы фактически выполняете побитовое И &
над значениями:
myProperties.AllowedColors: 00001110
MyColor.Green: 00000010
-----------------------
00000010 // Hey, this is the same as MyColor.Green!
Значение None = 0
А что касается использования 0
в вашем перечислении цитаты из MSDN:
[Flags]
public enum MyColors
{
None = 0,
....
}
Используйте None в качестве имени константы перечисляемого флага, значение которой равно нулю. Вы не можете использовать перечисляемую константу None в побитовой операции AND для проверки флага, потому что результат всегда равен нулю. Однако вы можете выполнить логическое, а не побитовое сравнение между числовым значением и константой None для перечисления, чтобы определить, установлены ли какие-либо биты в числовом значении.
Вы можете найти больше информации об атрибуте flags и его использовании в msdn и о разработке флагов в msdn