Clearing Enum Flags

 
Via Krzysztof Cwalina -
 

Somebody just pointed out to me that the enum guidelines don’t provide any information on how to clear a flag in a flags enum variable.

This is quite easy to do if the enum has a value (member) that has all the flags set. Such value is usually called All.

[Flags]

public enum Foos {

    A = 1,

    B = 2,

    C = 4,

    D = 8,

    AB = A | B,

    CD = C | D,

    All = AB | CD

}

 

static class Program {

    static void Main() {

        Foos value = Foos.AB;

        Console.WriteLine(ClearFlag(value,Foos.A);

    }

 

    public static Foos ClearFlag(Foos value, Foos flag) {

        value = value & (Foos.All ^ flag);

        return value;

    }

}

If the enum does not contain the All value, you can manually create it by combining existing flags.

    public static Foos ClearFlag(Foos value, Foos flag) {

        value = value & ((Foos.AB|Foos.CD) ^ flag);

        return value;

    }

Or you can manufactore the All value from UInt32.  

    public static Foos ClearFlag(Foos value, Foos flag) {

        Foos all;

        unchecked {

            all = (Foos)UInt32.MaxValue;

        }

        value = value & (all ^ flag);

        return value;

    }

Keep in mind that not all enums are backed with 32-bit integers. For these that are larger, for example enums with ulong as the underlying type, you will need to use UINt32.MaxValue instead.

 

    [Flags]

    public enum Foos : ulong {

    }

 

    public static Foos ClearFlag(Foos value, Foos flag) {

        Foos all;

        unchecked {

            all = (Foos)UInt64.MaxValue;

        }

        value = value & (all ^ flag);

        return value;

    }

 

What’s interesting is that you don’t actually need to change anything if the underlying type is smaller, i.e. you can cast UInt64 to an enum backed with a byte. The cast operator takes care of the size mismatch. This means you could always use UInt64.  The only drawback would be that it makes the variable all larger than it has to be, which is a slight inefficiency, probably not detectable in all but the most targeted benchmarks.

 
Published Tuesday, August 29, 2006 9:31 PM by dotnetboy2003
Filed under:

Comments

# re: Clearing Enum Flags

Isn't it easier to just "and" the compliment of the flag? i.e. value & ~flag

Wednesday, August 30, 2006 12:48 AM by jonny

# re: Clearing Enum Flags

What's wrong with value = (Foos)0?

Shouldn't you be using (Foos)-1 instead (Foos)<whatevertype>.MaxValue?

Wednesday, August 30, 2006 4:21 AM by Paulo Morgado

# re: Clearing Enum Flags

Or create an enum value:

None=0,

...

That way it will also be the default if it hasn't been set explicitly. Feels more intuitive to me.

Wednesday, August 30, 2006 6:27 AM by Wim