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

Asked

Viewed 2,594 times

9

I was seeing how the class works FileInfo 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 is this attribute [Flags] ago?

  • This link does not answer anything, but it is about a question I asked regarding the use of [Flags], It is at complement level (: http://answall.com/questions/12835/howto show correct name-em-um-enum-bitwise

2 answers

16


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

To add a value use the operator:

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

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

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

To remove a value use operator NOT:

rgb &= ~Cores.Azul;

Enum.Hasflag *

If you are using . NET 4 or higher you can use the method Hasflag to check if the Enum value in the past is in the combination:

if (rgb.HasFlag(Cores.Azul))

Beware of nay multiples of two

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

That is, if any of the values is 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 possess not only the flags Ciano, Magenta and Amarelo as it will also possess Vermelho, Verde and Azul:

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

But... and the attribute Flags after all?

Notice that so far we don’t talk 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 is:

  • It changes the behavior of certain methods such as Format and Tostring.
  • It is especially useful in languages other than C#, such as VB, that do not support operations bitwise to language level.
  • Although it doesn’t do much, it turns out to be good practice because it shows that the intention of Enum is to be used in this way.

* Although the documentation specifies that the method Hasflag only works with enums marked with Flagsattribute, according to my tests worked normally with an unmarked Enum. 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.

  • I didn’t know the HasFlag, very interesting.

5

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
}

* No problem using the operator <<, because in this case the values are solved at compile time.

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

// 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 the two 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 may 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)

For

// 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;

For

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

More about C# operators on MSDN.

  • +1 for the use of the operator <<

Browser other questions tagged

You are not signed in. Login or sign up in order to post.