C# Enums – Is It Wrong to Use Flags for Grouping Enums?

cenumnetreadability

My understanding is that [Flag] enums are typically used for things that can be combined, where the individual values aren't mutually exclusive.

For example:

[Flags]
public enum SomeAttributes
{
    Foo = 1 << 0,
    Bar = 1 << 1,
    Baz = 1 << 2,
}

Where any SomeAttributes value can be a combination of Foo, Bar and Baz.

In a more complicated, real-life scenario, I use an enum to describe a DeclarationType:

[Flags]
public enum DeclarationType
{
    Project = 1 << 0,
    Module = 1 << 1,
    ProceduralModule = 1 << 2 | Module,
    ClassModule = 1 << 3 | Module,
    UserForm = 1 << 4 | ClassModule,
    Document = 1 << 5 | ClassModule,
    ModuleOption = 1 << 6,
    Member = 1 << 7,
    Procedure = 1 << 8 | Member,
    Function = 1 << 9 | Member,
    Property = 1 << 10 | Member,
    PropertyGet = 1 << 11 | Property | Function,
    PropertyLet = 1 << 12 | Property | Procedure,
    PropertySet = 1 << 13 | Property | Procedure,
    Parameter = 1 << 14,
    Variable = 1 << 15,
    Control = 1 << 16 | Variable,
    Constant = 1 << 17,
    Enumeration = 1 << 18,
    EnumerationMember = 1 << 19,
    Event = 1 << 20,
    UserDefinedType = 1 << 21,
    UserDefinedTypeMember = 1 << 22,
    LibraryFunction = 1 << 23 | Function,
    LibraryProcedure = 1 << 24 | Procedure,
    LineLabel = 1 << 25,
    UnresolvedMember = 1 << 26,
    BracketedExpression = 1 << 27,
    ComAlias = 1 << 28
}

Obviously a given Declaration can't be both a Variable and a LibraryProcedure – the two individual values can't be combined.. and they're not.

While these flags are extremely useful (it's very easy to verify whether a given DeclarationType is a Property or a Module), it feels "wrong" because the flags aren't really used for combining values, but rather for grouping them into "sub-types".

So I'm told that this is abusing enum flags – this answer essentially says that if I have a set of values applicable to apples and another set applicable to oranges, then I need a different enum type for apples and another one for oranges – the problem with that here is that I need all declarations to have a common interface, with DeclarationType being exposed in the base Declaration class: having a PropertyType enum wouldn't be useful at all.

Is this a sloppy/surprising/abusive design? If so, then how is that problem typically solved?

Best Answer

This is definitely abusing enums and flags! It might work for you, but anybody else reading the code is going to be mightily confused.

If I understand correctly, you have a hierarchical classification of declarations. This is far to much information to encode in a single enum. But there is an obvious alternative: Use classes and inheritance! So Member inherits from DeclarationType, Property inherits from Member and so on.

Enums are appropriate in some particular circumstances: If a value is always one of a limited number of options, or if it is any combination of a limited number of options (flags). Any information which is more complex or structured than this should be represented using objects.

Edit: In your "real-life scenario" it seems there are multiple places where behavior is selected depending on the value of the enum. This is really an antipattern, since you are using switch + enum as a "poor mans polymorphism". Just turn the enum value into distinct classes encapsulating the declaration-specific behavor, and your code will be much cleaner

Related Topic