What does an enum with the [Flags] attribute mean and how does it work?

I was seeing how class FileInfo works and came across an enum:

[Serializable]
[ComVisible(true)]
[Flags]
public enum FileAttributes
{
    ReadOnly = 1,
    Hidden = 2,
    System = 4,
    Directory = 16,
    Archive = 32,
    Device = 64,
    Normal = 128,
    Temporary = 256,
    SparseFile = 512,
    ReparsePoint = 1024,
    Compressed = 2048,
    Offline = 4096,
    NotContentIndexed = 8192,
    Encrypted = 16384,
    [ComVisible(false)]
    IntegrityStream = 32768,
    [ComVisible(false)]
    NoScrubData = 131072,
}

What does this attribute [Flags] do?

Author: Maniero, 2014-01-03

2 answers

You can use operations bitwise to combine different values into just one.

To add a value use the or operator:

var rgb = Cores.Vermelho | Cores.Verde | Cores.Azul;

To check if a value is present use the and operator (see HasFlag method below):

if ((rgb & Cores.Azul) == Cores.Azul)

To remove a value use the operator not :

rgb &= ~Cores.Azul;

Enum.HasFlag *

If you are using .NET 4 or higher you can use the hasflag to check if the value of the passed enum is in the combination:

if (rgb.HasFlag(Cores.Azul))

Beware of not multiples of two

As you may have noticed, the combination is done with the bits of each combined value.

That is, if any of the values are not multiple of two you may be combining several flags at once.

Example:

public enum Cores
{
    Vermelho = 1, // Cor primária.
    Verde = 2, // Cor primária.
    Amarelo = 3, // Cor segundária. Mistura de vermelho com verde (1 & 2).
    Azul = 4, // Cor primária.
    Magenta = 5, // Cor segundária. Mistura de vermelho e azul (1 & 4).
    Ciano = 6 // Cor segundária. Mistura de verde e azul (2 & 4).
}

 

var cores = Cores.Ciano | Cores.Magenta | Cores.Amarelo;

The variable cores will have not only the flags Ciano, Magenta and Amarelo as will also have Vermelho, Verde e Azul:

cores.HasFlag(Cores.Vermelho); // True
cores.HasFlag(Cores.Verde); // True
cores.HasFlag(Cores.Azul); // True

Mas... what about the Flags attribute anyway?

Notice that so far we have not talked about the attribute Flags. Everything that has been said so far works without enum being marked with the attribute.

The difference between an enum marked with Flags and an unmarked one is:

  • it changes the behavior of certain methods like Formatand ToString.
  • is especially useful in languages other than C#, such as VB, which do not support operations bitwise to language level.
  • although it does not do much, it turns out to be a good practice because it demonstrates that the intention of enum is to be used in this way.

* although the documentation states that the method hasflag only works with enums marked with FlagsAttribute, according to my tests it worked normally with an enum not marked. Anyway follows the excerpt:

The HasFlag method is designed to be used with enumeration types that are marked with the FlagsAttribute attribute and can be used to determine whether multiple bit fields are set. For enumeration types that are not marked with the FlagsAttribute attribute, call either The Equals method or the CompareTo method.

 14
Author: talles, 2014-01-03 20:19:34

An enum with this attribute allows you to put multiple values into a single variable. For example:

var atributosDoArquivo = FileAttributes.ReadOnly | FileAttributes.Hidden;

The enum marked with the attribute [Flags] works by doing operations bitwise , i.e. in a simpler example:

[Flags]
public enum MeuEnum
{
    Um   = 1 << 0,       // 1
    Dois = 1 << 1,       // 2
    Tres = 1 << 2,       // 4
}

* it's okay to use the << operator, as in this case the values are resolved at compile time.

Note that for correct operation you need to put the bit in the correct position, peas:

// valores do enum
Um   = 00000001
Dois = 00000010
Tres = 00000100

So when we assign two values of this enum to a variable, the result will be:

var resultado = MeuEnum.Um | MeuEnum.Tres; // 00000101

Both the bit of Um and Tres are present in the result, so this variable contains both values.


If your variable has more than one value and you want to know if it contains only one value, you should not compare the variable directly as you might have thought to do, because if it contains more than one value your condition will fail.

To find out if resultado has Um and any other value, compare this way:

if ((resultado & MeuEnum.Um) == MeuEnum.Um)

Peas

// resultado & MeuEnum.Um == MeuEnum.Um
(00000101 & 00000001) = 00000001

If you want to remove only one value while keeping all others, you can use:

resultado &= ~MeuEnum.Um;

Peas

// resultado & inverso de Um = Tres
00000101     & 11111110      = 00000100

More here about operators in C# on MSDN .

 5
Author: BrunoLM, 2014-01-03 18:13:28