Use Enum’s with caution

In C# the class Enum is often used. Some geek’s argue that the Enum’s “improve code clarity and and reduce the probability of invalid values. … Enum’s are self-documenting.

Enum’s should be used with caution, since some things are not straight-forward. The following article will show you where to be cautious.

What the MSDN documentation says about enum’s:

“The enum keyword is used to declare an enumeration, a distinct type that consists of a set of named constants called the enumerator list. Every enumeration type has an underlying type, which can be any integral type except char. The default underlying type of the enumeration elements is int. By default, the first enumerator has the value 0, and the value of each successive enumerator is increased by 1. For example:”

Enum as a Different Type than Integer

internal enum Color : short

Why would I define an enum as short, UInt32 or as Byte? I believe this is a legacy thing because the enum is mostly used to define the values for the Win32 API.

Using Enum as Flags

[Flags]
internal enum ParseFlags
{
  HaveYear  = 0x00000001,
  HaveMonth = 0x00000002,
  HaveDay  = 0x00000004
}

If you are using enum as Flags, make sure you only use values as the power of 2 only. That will not be enforced and leads to errors when you define for example a value of 3 in the example above.

Enum does not provide Type Safety

If you think enum’s are type safe, you will get into deep trouble. Look at the example code below. The enum that we have defined is 1, 2 and 3. Right?
Now try to call

new EnumTricks.IsVolumeHigh((Volume)27);

That should fail, at least at runtime. It didn’t? That’s really strange… The wrong call will not be detected during compilation nor during runtime. You feel yourself in a false safety.

public enum Volume
{
  Low = 1,
  Medium,
  High
}

public class EnumTricks
{

  public bool IsVolumeHigh(Volume volume)
  {
    var result = false;

    switch (volume)
    {
      case Volume.Low:
        Console.WriteLine("Volume is low.");
        break;

      case Volume.Medium:
        Console.WriteLine("Volume is medium.");
        break;

      case Volume.High:
        Console.WriteLine("Volume is high.");
        result = true;
        break;
    }

    return result;
  }
}

Workaround: Use Enum.IsDefined to find out, if the int value is in the defined range of the enum value.

Enum Conversion

Have you ever tried to convert from enum to int, int to enum, string to enum, string to int value of enum? I’ll show you here with the Volume enum from above, but I didn’t check for the:

public int EnumToInt(Volume volume)
{
  return (int)volume;
}

public Volume IntToEnum(int intValue)
{
  return (Volume)intValue;
}

public Volume StringToEnum(string stringValue)
{
  return (Volume)Enum.Parse(typeof(Volume), stringValue);
}

public int StringToInt(string stringValue)
{
  var volume = StringToEnum(stringValue);
  return EnumToInt(volume);
}

Enum’s have a low Extensibility

Whenever you need integer values to be extensible, don’t choose enum for that. The reason is that you need to change the code to extend the enum. An example of extensible reference values are zip codes. They change and extend frequently.

Solution: One alternative solution is the usage of reference codes. With reference codes you have a code (your identifier) and a value that you will use to show to the user. For example the currencies as defined in the ISO standard define a classical reference code. The list of possible values can be stored in the database or in a file, which both are easy to extend and update.

How to use Enum’s?

What are the enum’s used for in real projects? Often they are used to control the behavior of methods within classes.

public enum Configuration
{
  Debug,
  Release
}

public class Logger
{
  public void Log(Configuration configuration, string logMessage)
  {
    switch (configuration)
    {
      Debug:
        InternalLog("DEBUG: " + logMessage);
        break;

      Release:
        InternalLog(logMessage);
        break;
    }
  }

  private void InternalLog(string logMessage)
  {
    ...
  }

}

This could easily be rewritten (I leave it to you as an exercise to fully implement the example):

public class DebugLogger : AbstractLogger
{
  ...
}

public class ReleaseLogger : AbstractLogger
{
  ...
}

Good choice of Enum’s?

Every time you have a fixed list of integer values which are not used to control your flow of instructions, you may use an enum. We could discuss the usage for the gender (Male, Female, Undefined) or for month of the year (January, February … December). But with the last example I already have the bad feeling of internationalization. Will the string representation of the enum represent the key for the resources?

Conclusion

Whenever you use enum’s please use them with caution and a clear goal in mind. Many developers will use you code at some point in time and they might not be aware of the strange things in enum’s.

See also Urs Enzler’s article about Top 10 of Software Design Evilness.


About the author

16 comments

  • What a load of piffle.

    Anything that can be used badly can be used badly. So what. Enums do help document. Just because some people don’t bother to learn how they work properly doesn’t mean that they are evil.

    I reckon you have just bothered to read up on enums and have found why your badly written code doesn’t work and want a rant. Let’s go through your points.

    Strange Thing #1:

    You must be angry or something not to realise that the Intellisense is indeed in alphabetical order.

    Strange Thing #2:

    Why define as a different type? Perhaps because you are interfacing with something that uses a different type. Perhaps you want to use a smaller value to minimise memory usage?

    Strange Thing #3:

    You don’t have to specify the flags attribute. You can still use the logical bitwise operators. If you do define Flags you get a couple of extra nice features, such as the conversion to string working properly for combined values.

    No Type Safety:

    Who ever said they were type safe? Why is this a problem as long as you understand? If you can’t be bothered to learn something properly, expect it to bite you.

    Conversion:

    What’s wrong with this?

    Bad Changeability:

    Nope, this guy’s a bad developer. Are you suggesting that the developer did a good job when he defined an enum that could not be extended? Or he created a system that was locked into enums and didn’t consider that the system may need an extra value? Fire him, he’s an idiot.

    Usage of Enums:

    Again, fire this guy. That’s a stupid use of enums. Or maybe send him on a course. I reckon I can take any part of a language and use it inappropriately. Does that make every language bad?

    Even your example of good usage suggests a bizarre loathing of a good concept. Why would you care about internationalisation when creating an enum. These are CONSTANTS for use internally, not strings for display to the user.

    Bad article, bad opinion, not well thought out.

  • #1: Not Enum’s fault.
    #2: Nonsensical.
    #3: Missing the point.
    #Bad Changeability: Huh?
    #Usage: Not Enum’s fault.
    #When not evil: Contradictory, see #3.

  • To say that enums are evil may be a bit provocative, but Enums are mostly not the best solution to solve a problem.
    If you have to control behaviour then use subclassing instead of switch case.
    If you have to identify a property then use reference codes.

    You can use enums, but the other options are much easier and powerful regarding extensibility, maintainability and readability.

    And using a sub-optimal solution although there is an obvious better one is defenitly evil 😉

    Using enums is like using a hammer for everything, instead of using a screw driver or scalpel when best suited.

  • @Urs,

    of course enums are mostly not the best solution to a problem. They are a solution to some problems though. I think in general that this article is rather ridiculous.

  • @Bob. Couldn’t agree more. The arguments are silly and the English is poor too.

  • Hy guys
    Interesting how this provocative article manages to seethe a discussion on our website. I really appreciate all the comments you guys are currently giving about this topic. But I must say that some of the comments are rather rude against the author. Please consider that the article is reflecting the author’s opinion about enums. Some agree and some might not agree…

    I personally think of enums not as plain evil programming construct but I think that enums can be safely used in code structures internally. Especially for frameworks that should be designed for extensibility the usage of enums should be avoided because polymorphism is the way to go.

    Looking forward for more controversial discussion 😉

    Daniel

  • If your any additional values would require your application to change, then you need a constant, or Enum for that matter. Example, addition of status to a certain type of record, which probably needs extra logics.

    If any addition of additional values should not affects how the application works (as in, just another value), then use reference files. Example, additional ISO currency value, which should not affects on how the application works.

    And one should not expose internationalization concerns to Enums. That’s just plain bad design IMO.

  • Hi, we are sorry that you didn’t like this article. If you would like to express your thoughts so that we can learn why you didn’t like it then don’t hesitate to give a comment here.

  • I can assure you that I hate enums as well. They have no place in an object oriented language.
    Every time I see enums used, a lot of spaghetti code has evolved around it because they simply are very stupid to build anything useful around.

    Enums should be removed from C#.

  • #6: Frank “just wants a new value on the interface”, but Darren doesn’t even know what that value is supposed to *mean* to the application. What should the application *do* when that value is encountered? Should it max out the speaker volume? Mute it? Treat it as though it were set to some system-wide default?

    Enums are ‘evil’, because Darren doesn’t allow a client to demand an immediate code change with no specification about what that change will *do*? Or because he won’t do it immediately, without any testing, or sign-off procedure?

    Seriously, as nonsensical as many of those complaints about Enums were, *that* one takes the cake.

  • My brother pointed me to this when he asked if using an enum in a switch statement for control flow was bad code. Every one of the examples of “evil” are based on a developer who didn’t know what they were doing or potential use is an absurd way. Enum classes would be a nightmare in certain situations such as serialization. They’re massively bloated, require 10 times more work, and not as maintainable compared to a regular enum and do not work a single bit better for things like control flow. We use them in WCF, mobile clients and other web services without issue for years now where millions upon millions of transactions are processed. Not a single time has anyone said or even hinted “oh my, we used an enum and it hosed us”.

    Yes, enum classes have their place but making a blanket claim IMO displays a serious lack of knowledge or experience in the real world.

  • Personally, I have never seen the point of enumeration in languages with definable data structures – they just seem to be completely unnecessary layer of abstraction! Increased code readability is a highly dubious argument to support their use – #defines work just fine for me. As you rightly state, they provide a (non-obvious) means to circumvent data types and many compilers won’t even issue a warning!
    Use enums with caution.

By Thomas

Recent Posts