Enumeration classes

A question came up on the ALT.NET message board asking whether Value Objects should be used across service boundaries.  Of course, the conversation took several detours, eventually coming to the question, “what do you do about enumerations crossing service boundaries.”  I’m still ignoring that question, but I’ve found different ways to represent enums in my model.  Now, enums are just fine in lots of scenarios, but quite poor in others.  There are other options I like to use when enumerations break down, and many times in the domain model, I go straight to the other option.

For example, I’ve seen quite a few models like this:

public class Employee
{
    public EmployeeType Type { get; set; }
}

public enum EmployeeType
{
    Manager,
    Servant,
    AssistantToTheRegionalManager
}

The problem with a model like this is it tends to create lots of switch statements:

public void ProcessBonus(Employee employee)
{
    switch(employee.Type)
    {
        case EmployeeType.Manager:
            employee.Bonus = 1000m;
            break;
        case EmployeeType.Servant:
            employee.Bonus = 0.01m;
            break;
        case EmployeeType.AssistantToTheRegionalManager:
            employee.Bonus = 1.0m;
            break;
        default:
            throw new ArgumentOutOfRangeException();
    }
}

There are a few problems with enumerations like this:

  • Behavior related to the enumeration gets scattered around the application
  • New enumeration values require shotgun surgery
  • Enumerations don’t follow the Open-Closed Principle

Adding a new enumeration value is quite a large pain, as there are lots of these switch statements around to go back and modify.  In the case above, we want the “default” behavior for defensive coding purposes, but a new enumeration value will cause an exception to be thrown.

With enumeration behavior scattered around, we can never bring it back to the source type, because enumeration types can’t have any behavior (or state for that matter).

Instead of an enumeration, I like to use an enumeration class.

Creating the enumeration class

To move away from an enumeration to an enumeration class, I’ll first use the Enumeration layer supertype from our “default architecture” we use at Headspring, from Tarantino:

public abstract class Enumeration : IComparable
{
    private readonly int _value;
    private readonly string _displayName;

    protected Enumeration()
    {
    }

    protected Enumeration(int value, string displayName)
    {
        _value = value;
        _displayName = displayName;
    }

    public int Value
    {
        get { return _value; }
    }

    public string DisplayName
    {
        get { return _displayName; }
    }

    public override string ToString()
    {
        return DisplayName;
    }

    public static IEnumerable<T> GetAll<T>() where T : Enumeration, new()
    {
        var type = typeof(T);
        var fields = type.GetFields(BindingFlags.Public | BindingFlags.Static | BindingFlags.DeclaredOnly);

        foreach (var info in fields)
        {
            var instance = new T();
            var locatedValue = info.GetValue(instance) as T;

            if (locatedValue != null)
            {
                yield return locatedValue;
            }
        }
    }

    public override bool Equals(object obj)
    {
        var otherValue = obj as Enumeration;

        if (otherValue == null)
        {
            return false;
        }

        var typeMatches = GetType().Equals(obj.GetType());
        var valueMatches = _value.Equals(otherValue.Value);

        return typeMatches && valueMatches;
    }

    public override int GetHashCode()
    {
        return _value.GetHashCode();
    }

    public static int AbsoluteDifference(Enumeration firstValue, Enumeration secondValue)
    {
        var absoluteDifference = Math.Abs(firstValue.Value - secondValue.Value);
        return absoluteDifference;
    }

    public static T FromValue<T>(int value) where T : Enumeration, new()
    {
        var matchingItem = parse<T, int>(value, "value", item => item.Value == value);
        return matchingItem;
    }

    public static T FromDisplayName<T>(string displayName) where T : Enumeration, new()
    {
        var matchingItem = parse<T, string>(displayName, "display name", item => item.DisplayName == displayName);
        return matchingItem;
    }

    private static T parse<T, K>(K value, string description, Func<T, bool> predicate) where T : Enumeration, new()
    {
        var matchingItem = GetAll<T>().FirstOrDefault(predicate);

        if (matchingItem == null)
        {
            var message = string.Format("'{0}' is not a valid {1} in {2}", value, description, typeof(T));
            throw new ApplicationException(message);
        }

        return matchingItem;
    }

    public int CompareTo(object other)
    {
        return Value.CompareTo(((Enumeration)other).Value);
    }
}

It’s a large class, but it gives us some nice functionality out of the box, such as equality operations and such.  Next, I’ll create the subtype that will house all of my different enumeration values:

public class EmployeeType : Enumeration
{
}

I’d still like individual employee types, such as Manager and Servant, and I can do this by exposing static readonly fields representing these employee types:

public class EmployeeType : Enumeration
{
    public static readonly EmployeeType Manager 
        = new EmployeeType(0, "Manager");
    public static readonly EmployeeType Servant 
        = new EmployeeType(1, "Servant");
    public static readonly EmployeeType AssistantToTheRegionalManager 
        = new EmployeeType(2, "Assistant to the Regional Manager");

    private EmployeeType() { }
    private EmployeeType(int value, string displayName) : base(value, displayName) { }
}

Notice I also get a much nicer display name with spaces.  In the past, I always had to do a lot of finagling to put spaces in the names when I displayed them. When someone wants to assign the Employee’s type, it doesn’t look any different than before:

dwightSchrute.Type = EmployeeType.AssistantToTheRegionalManager;

Now that I have a real class that acts like a Value Object, I have a destination for behavior.  For example, I can tack on a “BonusSize” property:

public void ProcessBonus(Employee employee)
{
    employee.Bonus = employee.Type.BonusSize;
}

Yes, this is a rather silly example, but it illustrates that most, if not all, of the switch statements concerning the previous enum type go away.  The behavior can be pushed down into the enumeration class, with each specific enumeration type supplying specific behavior.

This pattern can even be taken further, where I have subtypes for each individual EmployeeType.  I’ll never need to expose them outside to anyone:

public abstract class EmployeeType : Enumeration
{
    public static readonly EmployeeType Manager 
        = new ManagerType();

    protected EmployeeType() { }
    protected EmployeeType(int value, string displayName) : base(value, displayName) { }

    public abstract decimal BonusSize { get; }

    private class ManagerType : EmployeeType
    {
        public ManagerType() : base(0, "Manager") { }

        public override decimal BonusSize
        {
            get { return 1000m; }
        }
    }
}

All of the variations of each enumeration type can be pushed down not only to the enumeration class, but to each specific subtype.  The BonusSize now becomes an implementation detail of individual EmployeeType.

Enumerations work well in a variety of scenarios, but can break down quickly inside your domain model.  Enumeration classes provide much of the same usability, with the added benefit of becoming a destination for behavior.

Switch statements are no longer necessary, as I can push that variability and knowledge where it belongs, back inside the model.  If for some reason I need to check specific enumeration class values, the option is still open for me.  This pattern shouldn’t replace all enumerations, but it’s nice to have an alternative.

Related Articles:

Post Footer automatically generated by Add Post Footer Plugin for wordpress.

About Jimmy Bogard

I'm a technical architect with Headspring in Austin, TX. I focus on DDD, distributed systems, and any other acronym-centric design/architecture/methodology. I created AutoMapper and am a co-author of the ASP.NET MVC in Action books.
This entry was posted in C#, Domain-Driven Design. Bookmark the permalink. Follow any comments here with the RSS feed for this post.
  • Ryan

    Congratulations, you’ve discovered strategy pattern.

  • http://www.peterRitchie.com/blog Peter Ritchie

    I think that it’s unwise to think of enums with behaviour. Simple inheritance does the trick in almost all cases. It’s relevant that an int value is the key for the particular type. It should simply be an immutable type. For example, I can derive EmployeeType from Enumeration and PhoneType from Enumeration and now use them both where an Enumeration can be used; clearly they’re not related and shouldn’t be usable like that. i.e. Liskov

    But, I would have more closely matched Enum: Parse/TryParse instead of FromDisplayName (throwing FormatException from Parse instead of generally-deprecated ApplicationException), GetName instead of DisplayName, GetValues in stead of GetAll, and AbsoluteDifference seems to not be a responsibility of an enumeration

  • Jeremy Gray

    @Ryan/Jimmy – and Replace Conditional with Polymorphism.
    ;)

  • http://mbrownchicago.spaces.live.com Mike Brown

    @Ryan…on it’s head the nail you hit.

    Jimmy,

    I would argue that the issue is not with using an Enumeration itself but with the fact that ProcessBonus is external to the Employee. Also, the bonus processing probably would have more logic in it than just the type of employee.

    By moving away from the Enumeration, you lose some of its benefits, specifically being able to put a new value in between two existing values, using it as a parameter in an Attribute, and of course the most underused application of enums: flags.

  • Jason

    kudos for “The Office” references :)

    not sure if this is an issue with >3.0 but with 2.0 the new generic constraint fails along with GetAll. with a private ctor on the subclass. here is the modification
    public static IEnumerable
    GetAll() where T : Enumeration
    {
    Type type = typeof (T);
    FieldInfo[] fields = type.GetFields(BindingFlags.Public | BindingFlags.Static | BindingFlags.DeclaredOnly);
    foreach (FieldInfo field in fields)
    {
    T instance = (T) Activator.CreateInstance(typeof (T), true);
    T locatedValue = field.GetValue(instance) as T;

    if (locatedValue == null) continue;
    yield return locatedValue;
    }
    }
    I also needed to remove the new constraint of the other public static members.

  • Jonathan Allen

    That is just plain silly.

    You can continue to use enumerations and still keep your code in one place (ok, really two places).

    You have the Enumeration itself define the values and match it with a Module (C# static class) that has all the operations on it.

    With Extension Methods (VB 9/C# 3) you even get method-like syntax on the enumerations

  • http://jimmybogard.lostechies.com Jimmy Bogard

    @Ryan

    Did I say I discovered a new pattern? I wasn’t trying to. Enumeration classes are an old concept. I often use things like template method as well.

  • http://jimmybogard.lostechies.com Jimmy Bogard

    @Peter

    I didn’t follow your first arguments. Each implementation is immutable, as they have become DDD-style Value Objects.

  • http://jimmybogard.lostechies.com Jimmy Bogard

    @Jeremy Gray

    Yep, here’s the source:

    http://www.refactoring.com/catalog/replaceConditionalWithPolymorphism.html

    With the twist of refactoring away from an enum. Forgot to cite that one…

  • http://jimmybogard.lostechies.com Jimmy Bogard

    @Mike

    There are definitely places for enums, but I’ve seen quite a bit of overuse just to have a type that presents a set of valid choices. Aaaaand it could have helped to pick a better example. I’ve just found myself scrutinizing my choices more when an enum comes up in the model.

    I have had some examples where a single new enum required two dozen changes in switch statements. That’s when I knew I was modeling it poorly.

  • http://jimmybogard.lostechies.com Jimmy Bogard

    @Jason

    Yep, this is in .NET 3.5, C# 3.0. Though I wasn’t aware of these changes in generic constraints in 3.0, good to know.

  • http://jimmybogard.lostechies.com Jimmy Bogard

    @Jonathan Allen

    Well, silly or not, it’s a better model in some cases. I like to keep behavior related to a type, on that type, and not have helper classes around. Users still need to know about the helper class to get the functionality.

    Plus, a class gives me the ability to add more state information. It’s definitely not valid in all choices, but inside my domain model, it seems to make more sense.

  • http://www.jeffdoolittle.com Jeff

    It seems to me that a good rule of thumb is to consider this refactoring when you are about to create a switch statement for an enum. Many switch statements for enums just seem to be spewing logic across an application that ought to be encapsulated anyway.

  • http://blog.spontaneouspublicity.com Luke Foust

    It seems like you didn’t really do away with the code in the switch statement. Instead, you just distributed the code out to a bunch of overridden properties in the sub classes. I do find the idea of making your own enumeration class useful sometimes but mostly I just try to stick with the plain old enums (POE?)

  • Dan Malcolm

    I’ve used this kind of uber enum to add display and utility methods to “lookup” type classes, but I’d avoid adding domain logic to this class.

    A useful way to avoid the switch statements when you _do_ need to apply different logic according to value of an enum property is:

    public class SalaryService
    {
    private Dictionary _bonusCalculators = new … [sore wrists...];

    private void InitBonusCalculators()
    {
    … Initialise dictionary (or maybe they are injected via IOC)
    }

    public Money CalculateBonus(Employee employee)
    {
    return _bonusCalculators[employee.EmployeeType].Calculate(employee);
    }
    }

    A Dictionary> can also be more concise where the logic of each alternative is pretty much fixed.

  • Jeffro

    I’ve always considered making the following changes when replacing “conditional with polymorphism” (using your example):

    public class Manager : Employee
    {
    }
    public class Servant : Employee
    {
    }
    public class AssistantToTheRegionalManager : Employee
    {
    }

    Do you see any pros/cons to use this approach vs your suggested approach of subclassing the Enumeration class?

    The act of instantiating one class type vs another would need to sit in another factory class/method, but I can’t see any other tradeoffs…

  • http://jimmybogard.lostechies.com Jimmy Bogard

    @Luke

    I like localizing behavior to the objects that concern them. Eliminating 12 switch statements for 3 classes is a nice trade, IMO.

  • http://jimmybogard.lostechies.com Jimmy Bogard

    @Jeffro

    The problem with this approach is when you have more than one aspect vary. Suppose in addition to Employee type/title, you have Employee status (FullTime, PartTime, etc). Any employee can be any title and any status, so having these vary independently (composition over inheritance) yields the most flexibility. But, this is assuming you have another aspect that varies.

    Inheritance in entities is a tricky beast, and I’ve been burned a couple of times doing something like that. But, I always seem to start out that way until I can see a hidden concept come out (like Employee Type or Status).

  • http://lieser-online.de Stefan Lieser

    How do you map such an Enumeration with NHibernate? If I map the Value property NH instantiates the class, but the DisplayName is missing (and of course a new object is created instead of using the corresponding static readonly field).

    Cheers,
    Stefan Lieser

  • http://www.crypt.co.za/ Twylite

    SELECT displayName, bonus FROM t_employee_types WHERE id = ?

    Your business rules are now in one place, and they aren’t hard-coded. You also have a list of employee types available for your UI.

    The only value of enums is compile-time safety. This means that if you introduce a new value to an enum you must necessarily change the source code (in various places) to use the new value in some way, which in turn means that an enum value should be associated with a behaviour not just a data set (or you’re just wasting everyone’s time).

  • http://jimmybogard.lostechies.com Jimmy Bogard

    @Stefan

    We use discriminators to map in NHibernate. This lets us map key values (or non-key values) to specific classes.

    The new object created is just fine, as we’ve implemented Value Object behavior (equality based on Value, not Reference). So an instance of ManagerType always equals another instance of ManagerType, even if they don’t point to the same reference in memory.

  • http://jimmybogard.lostechies.com Jimmy Bogard

    @Twylite

    That definitely works for a lot of scenarios, but not all. If the calculation cannot be configured through data in a table, you won’t be able to do this.

    One scenario we just ran into was that the Bonus calculation couldn’t be encapsulated in the database. We still had to use a BonusStrategy to link up to specific ways to calculate bonuses. This was all done seamlessly through NHibernate discriminators (i.e., there was no factory with a ginormous switch statement, just NHib loading up the _right_ strategy).

  • http://colinjack.blogspot.com Colin Jack

    @Ryan
    See TYPESAFE ENUM pattern for discussion.

    @Jimmy
    “I have had some examples where a single new enum required two dozen changes in switch statements. That’s when I knew I was modeling it poorly.”

    I largely I agree but I also find in larger domains you want to be careful that the typesafe enums don’t end up being function bags themsevles. For example if processing bonsues is complex or not just based on the EmployeeType then putting it in an EmployeeType quickly becomes ugly (at which point you put in place another set of STRATEGY style objects).

    Just mention as its an issue I’ve met a few times, never happy with the result as either I put all sorts of behavior in the TYPESAFE ENUM or I end up with a switch somewhere (e.g. to decide what BonusStrategy to return for an Employee).

    @Dan Malcolm
    Yeah thats an alternative I’ve used and seen good devs use too, handles nicely case where although ICalculationStrategy is based on EmployeeType you don’t want to directly associate them.

    For example maybe all but two EmployeeTypes share the calculation strategy, or type of calculation strategy is not just based on EmployeeType, or for design reasons you don’t want an EmployeeType to be coupled to a calculation strategy.

    Might be other reasons, those are the ones that come to mind. Anyway its just another tool and in no way replaces Typesafe enum in my view.

    @Jeffro
    As Jimmy says inheritance here is not a good option for these situations.

  • http://lieser-online.de Stefan Lieser

    @Jimmy
    Can you show an example mapping please?

    If have a property of type EmployeeType in class Employee, and EmployeeType has public static fields as you’ve shown in your example, how do I map this property in class Employee?

  • http://jimmybogard.lostechies.com Jimmy Bogard

    @Stefan

    Sure, no prob. I’ll whip something up in the next day or so.

  • ShadiMari

    Jimmy, would you please tell how to do mapping in nhibernate for the question posted by Stefan.

  • Arnis L.

    I’m quite sure this:

    public static readonly EmployeeType Manager
    = new EmployeeType(0, “Manager”);
    public static readonly EmployeeType Servant
    = new EmployeeType(1, “Servant”);
    public static readonly EmployeeType AssistantToTheRegionalManager
    = new EmployeeType(2, “Assistant to the Regional Manager”);

    Can be rewritten as:

    public static readonly EmployeeType
    Manager = new EmployeeType(0, “Manager”),
    Servant = new EmployeeType(1, “Servant”),
    AssistantToTheRegionalManager = new EmployeeType(2, “Assistant to the Regional Manager”);

    Looks a bit better and more enum-like. :)

  • http://www.lostechies.com/members/bogardj/default.aspx bogardj

    @Arnis

    Thanks for the tip! I never remember the default visibility rules on things like this :P

  • http://rohancragg.co.uk Rohan Cragg

    CodeCampServer source also has a variation of Enumeration class with a couple of handy helpers: FromValueOrDefault and FromDisplayNameOrDefault.

    http://code.google.com/p/codecampserver/source/browse/trunk/src/Core/Bases/Enumeration.cs

  • Adrian

    If ManagerType is hidden, and has extra functionality, how can you Serialize (xml Serialize in my case) an EmployeeType and then deserialize it to the right type (preserving the extra functionalities)?
    I guess you can get a MangerType back only by a static method, FromValue … like Rohan’s example, but how to make that work with serialization ?

  • http://eliasbland.wordpress.com Rupert Bates

    I really like this approach. I found though that to get equality working correctly in NHibernate Linq queries as I had to override the == operator on Enumeration as follows:

    public static bool operator == (Enumeration a, Enumeration b)
    {
    if ((object)a == null && (object)b == null) return true;
    if ((object)a == null || (object)b == null) return false;
    return a.Id == b.Id;
    }

  • Pingback: My Experience at Orlando Code Camp 2011RepeatGeek

  • Anonymous

    Great. Love this approach!

  • Pingback: Becoming a Headspringer: Take Advantage of Working with Smart People | Headspring

  • Pingback: Persisting enumeration classes with NHibernate | Jimmy Bogard's Blog

  • Anonymous Coward

    Very cool. I was sitting around slowly coming around to the fact that enum types are very smelly, so seeing this gives me ideas of how to refactor them properly

  • http://hammerproject.com/ matt kocaj

    Forgive my ignorance but I don’t understand why you’re ignoring the question ”
    what do you do about enumerations crossing service boundaries?”

    • Anonymous

      Man this post is like 4 years old. What do I do? Build normal .NET enums. Things that cross service boundaries are DTOs, so just data = enums only. Unless it’s behavioral objects getting consumed then yes, my tailor-made enum classes make it over.

      I ignored it cause I never needed to cross service boundaries but NOW I ARE ONE.

  • Ryan Vice

    Best thing I’ve seen on the web in ages. Great technique, thanks for sharing!

  • Pingback: Enumeration Classes and WCF « Outlawtrail – .NET Development

  • Pingback: Enumeration Classes as Flags « Outlawtrail – .NET Development

  • Brad Laney

    You need to fix the post to reflect changes for the new keyword. The new keyword requires PUBLIC default ctor. The static methods cannot execute.

    • anti nuke

      What worked for me was(after removing all the new())constraints from other methods was replacing in public static IEnumerable GetAll() this:

      var instance = new T();
      with
      var instance = (T)Activator.CreateInstance(typeof(T), true);
      with the ‘true’ parameter of CreateInstance allowing it to instantiate classes with non-public constructors.
      public static IEnumerable GetAll() where T : Enumeration
      {
      var type = typeof(T);
      var fields = type.GetFields(BindingFlags.Public | BindingFlags.Static | BindingFlags.DeclaredOnly);

      foreach (var info in fields)
      {
      var instance = (T)Activator.CreateInstance(typeof(T), true);

      var locatedValue = info.GetValue(instance) as T;

      if (locatedValue != null)
      {
      yield return locatedValue;
      }
      }
      }
      Works like a charm for me. And cudos to Jimmy for a great article!

      • Mauro

        Why do you create an instance (even worst in the foreach loop) of T? We don’t need any instance at all:

        public static IEnumerable GetAll() where T : Enumeration
        {
        var fields = typeof(T).GetFields(BindingFlags.Public | BindingFlags.Static | BindingFlags.DeclaredOnly);

        return fields.Select(f => f.GetValue(null)).Cast();
        }

  • Pingback: Polymorphism Part 2: Refactoring to Polymorphic Behavior | John Teague's Blog

  • Pingback: Is the enum class pattern incompatible with DI? | Stackforum

  • Mystcreater

    Very nice article even after more than 6 years. I just have one question: “How do you do dependency injection with this type of architecture?” I mean, injecting service or repository to query database or anything else outside of a simple money calculator. Thank you very much.

  • Mauro

    Nice article! There are a couple of issues in the code:

    1 – There’s no need to create any instance of T. You can remove all new() and use the following code for the GetAll:

    public static IEnumerable GetAll() where T : Enumeration
    {
    var fields = typeof(T).GetFields(BindingFlags.Public | BindingFlags.Static | BindingFlags.DeclaredOnly);

    return fields.Select(f => f.GetValue(null)).Cast();
    }

    2 – Now you can remove the empty constructors: they are useless and unwanted.

    Thanks for sharing!