Enum Alternatives in C#

Enum Alternatives in C#

Some time ago I wrote about Moving Beyond Enums and published an article on ASPAlliance by the same title. Unfortunately the latter article was largely screenshot-based, and those images seem to have disappeared, so I thought I’d revisit the topic here.

Enums are simple value-type flags that provide very minimal protection from invalid values and no behavior. They’re helpful in that they’re an improvement from magic numbers, but that’s about it. If you want to constrain the possible values a type might be, an enum can’t necessarily help you, since invalid types can still be provided. For example, this enum has four values and by default will have an int type. The values range from 0 to 3.

Now some method accepts this type as a parameter:

Many developers don’t realize that you should check that the incoming value is an actual, valid Role value. That’s because any int will work if you cast it:

What will role.ToString() print in this case? “10”. And if you have a switch or if-chain based on the enum type? Whatever it’s default case is, that’s the behavior invalid values will end up using.

Displaying enums in UI elements like DropDownLists is another challenge if they need to have spaces. In the example above, SalesRepresentative is fine as an enum label, but not great to present to the user. You can get around this using attributes, such as the System.ComponentModel.Description attribute, but really this is just putting lipstick on a pig. The larger issue is that enums don’t support behavior of any sort.

The type safe enum pattern addresses this. My friend Scott Depouw has a nice write-up of the pattern. It’s my preferred approach in most cases. The pattern creates a class to represent the enumeration, and can even use the same name and syntax so that a refactoring doesn’t require shotgun surgery. Converting the Roles enum above to the pattern might look like this (I’m changing Roles to Role in this case because I prefer the singular):

You can further extend types like this with additional behavior; Jimmy Bogard demonstrates a rich helper class in his Enumeration Classes article.

Using this Role type, you can constrain parameters much better than with an enum, and you can add whatever additional behavior you require. However, it’s not completely foolproof. Jon Skeet demonstrates a way in which a persistent coder could still manage to instantiate an instance of Role, despite its private constructor, violating the type safe enum pattern.

Update: For those looking for how to persist this pattern using an ORM like Entity Framework, I’ve written up how to persist type safe enums using EF6.

  • nbevans

    This is a poor mans version of a discriminated union. Just use F#.

    • ardalis

      Some day when we can have F# and C# side by side in the same project, I’d love to. In the meantime, having to create another project for F# is too much of a hassle in many cases.

      • nbevans

        I’ll add that to the list of “excuses for not upgrading to F#” 🙂

        • michael lang

          Upgrading? It’s like saying upgrading from a car to a motorbike. They’re just different.

      • Harry McIntyre

        Or you can use this: https://github.com/mcintyre321/OneOf 🙂

  • Greg Dennis

    This is very similar to my static converters for WPF. http://wp.me/p5Q7pK-P. Good read.

  • i do not agree with the above so much. trying to solve a problem by introducing other problems is not the way to go.
    – DoSomething((Shape)47) should never have been called by the developer
    – Enums can extended (extension method + attributes)
    – switch statement goes bye bye, which is a major deal breaker
    – and frankly it look’s pretty ugly
    my 2 cents

    • ardalis

      What actual problems are introduced? Getting rid of switch statements is a good thing – they’re a code smell, in many cases, and at best should appear only once (per decision) in a SOLID OO design (likely in a factory, determining which object to return that will perform an action). Extension methods are OK, but again can’t take advantage of any of the OO features of the language.

      • SOLID OO should remove some of the need of switch statement, in a ideal developer world. I am not living in one. Still Looks ugly and bye bye goes my Status int from the db and becomes a string? I am really not that sold on this proposal.

      • Going over the above code i have to set some things straight.

        “You can do this the following with enums
        var result = myObject.DoSomething((Roles)10);”

        but you can also do create a role with something like this
        Activator.CreateInstance(Type type, bool nonPublic)

        which means that you can instantiate a role with whatever data you like.
        so equality checks have to exist in order to guarantee that a Role is a Author making the implementation a lot bigger than it is.

        So let me summarize:
        * It is not safe as you can instantiate a Role with invalid Data
        * The implementation is a lot larger compared with a simple enum, not taken into account the needed equality implementation
        * the switch statement is gone (for us who don’t write always SOLID OO code 😉 )
        * The DB interaction has to be handled exclusively (mapping from and to value in db)

        Sorry for being negative but this adds more problems that it solves.

        • ardalis

          It’s true you can also use reflection rather than casting to create one of these Type Safe Enum instances, but you’d have to really *want* to do that. Whereas casting from numbers for enums is commonplace. You probably do it when you go to/from persistence, and again when you go to/from the UI (the numeric entry is likely the value used for dropdownlists, etc.). So, it’s 100x more likely to introduce problems than someone trying intently to use reflection to get an instance of a type. Reflection is powerful but by design it gets you around type safety, so you should only use it if you know what you’re doing and you’re aware there may be consequences in parts of the application that rely on type safety.

          Yes, this implementation is larger than an enum – only use it if you need more functionality than an enum affords. I’m not saying “Never use enums; always use this pattern.” What I’m saying is, if you’re stretching beyond what enums offer, this is a good upgrade.

          The DB implementation is straightforward and described here:
          http://ardalis.com/persisting-the-type-safe-enum-pattern-with-ef-6

          • thanks for the link, but i have already seen it since i follow your blog. You are correct about *wanting* to create a type in that way and that the casting is more common. I have used enums and extensions methods in order to accomplish most of the thinks mentioned, so i am quite happy with that and i can live with the danger of casting ints to enums. I will keep the above in mind if at some point i really need it. thanks very much.

  • John Scott

    I really don’t think anyone needs to worry about someone actually doing what Jon Skeet describes. Even typing the two sentences in which you bring it up is more effort than it’s worth.

    • ardalis

      Totally agree, but I thought it was interesting to see the hoops he was willing to jump through in order to get an instance from a private constructor.

  • Nice post – I find myself using this pattern quite regularly!

    One other thing to bear in mind is that unlike enums, these classes are nullable, so you may need to add null precondition checks where they were previously unnecessary.

    • ardalis

      True, good point. Thanks.

  • Satyajit Behera

    Hi, nice and useful. Is it also possible to do nesting of the class. If I have to maintain “Area” for “each role”, can I do that also? Suppose Author has another collection of “Area1”, “Area2″…… can I access that as Role.Author.Area1…. thanks.

    • ardalis

      Can you share some code, perhaps in a Gist or DotNetFiddle, that demonstrates your question? I’m not clear on what you’re asking.

  • Marco de Freitas

    Hi Steve,

    Loved your post, really useful information!!
    It got me thinking on one thing: this type of pattern may not be respecting the SRP?
    It feels to me the Role class is containing too much.
    I had seen a similar pattern on a book I read and I decided to write the code and see where it got me.
    I know this approach gives me more code spread but I’d like to know your opinion (or anyone else is also welcome!)

    • ardalis

      You could do this. I don’t see that you’re shifting any significant responsibilities (behavior) to your Author, Editor, Administrator, etc. types, though. They’re all the same. If at some point they each had their own distinct behavior, then I would be inclined to consider this refactoring, though. Otherwise, it seems perhaps premature.

      • Marco de Freitas

        Yes, I agree with you. I was thinking that every time you needed to add a new role you would have to add code inside your Role class, it seemed more reasonable to separate each role into a class also allowing for different behavior.
        But that is being premature in regard to the purpose of this post.
        Thanks for your opinion. 🙂

  • Naeem Sarfraz

    Steve, love this approach when I first came across it in Jimmy Bogards “Crafting Wicked Domain Models” talk at NDC.

    I think the three functions (List, FromString, FromValue) are missing the static keyword?