13

A developer at work recently started using a class pattern instead of enums in places where enums would usually fit. Instead, he uses something similar to that below:

internal class Suit
{
    public static readonly Suit Hearts = new Suit();
    public static readonly Suit Diamonds = new Suit();
    public static readonly Suit Spades = new Suit();
    public static readonly Suit Clubs = new Suit();
    public static readonly Suit Joker = new Suit();
    private static Suit()
    {

    }
    public static bool IsMatch(Suit lhs, Suit rhs)
    {
        return lhs.Equals(rhs) || (lhs.Equals(Joker) || rhs.Equals(Joker));
    }
}

His reasoning is that it invisibly looks like an enumeration, but allows him to contain the methods relating to the numeration (like the IsMatch above) to be contained within the enumeration itself.

He called this an Enumeration class, but it's not something I've ever seen before. I wondered what the advantages and disadvantages were and where I could find out more information?

Thanks

Edit: Another advantage he described was being able to add a specific ToString() implementation for the enumeration.

Chris Williams
  • 170
  • 1
  • 7
  • Well, you can't do this with an `enum` because you can't type an enum to a complex type. I guess this is the main reason for using something like this? – Ant P May 12 '13 at 12:35
  • The only real downside (besides some third party libraries not being too happy about it) I've encountered is that you can't (trivially) do a switch/case on the type. But then I've not used the technique extensively in C#. – Joachim Isaksson May 12 '13 at 12:39
  • Avoiding the switch statements was his main selling point actually. He used it to avoid what he described as monolithic switch statements. It is a point though that it stops you using them even when you want to. – Chris Williams May 12 '13 at 12:41
  • Sounds like he knows about Java enums... – Marc Gravell May 12 '13 at 12:59
  • you can find more information about the topic from Jimmy Bogard 's post [here](http://lostechies.com/jimmybogard/2008/08/12/enumeration-classes/) – Shashank May 12 '13 at 13:04
  • 1
    I think this post has your answer : [When to use enums, and when to replace them with a class with static members?][1] [1]: http://stackoverflow.com/questions/2119714/when-to-use-enums-and-when-to-replace-them-with-a-class-with-static-members – hm1984ir May 12 '13 at 13:06

3 Answers3

8

Enums are just fine in lots of scenarios, but quite poor in others. Usually I find some issues with Enums :

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

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).

In the other hand with an Enumeration Class:

All of the variations of each enumeration type can be pushed down not only to the enumeration class, but to each specific subtype.

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.

can read on that here

Rawdreeg
  • 461
  • 5
  • 12
  • related: https://learn.microsoft.com/en-us/dotnet/architecture/microservices/microservice-ddd-cqrs-patterns/enumeration-classes-over-enum-types – zwcloud Oct 26 '19 at 09:33
4

The main advantage of enums is that they are basically integers with some named values, as such they are inherently portable and serializable. Arithmetic and logical operations are also faster on enums.

Enumeration classes are used when you need an opaque value which has extra state information. For instance a generic Data Access Layer could have as an interface like:

public static class Dal
{
    public static Record Query(Operation operation, Parameters parameters);
}

var result = Dal.Query(Operation.DoSomething, new DoSomethingParameters {...});

To the users of the Dal Operation is just an enumeration of the operations available, but it could contain the connection string, the SQL statement or stored procedure and any other data needed by the generic Dal.

Another "common" use is for public modes in a system (a state or a strategy). From a user perspective the mode is an opaque value, but it may contain information or internal functionality crucial to the implementation of the system. A contrived example:


public class TheSystem
{
   public SystemMode Mode;
   public void Save()
   {
      Mode.Save();
   }
   public SystemDocument Read()
   {
      return Mode.Read();
   }
}

public abstract class SystemMode
{
   public static SystemMode ReadOnly = new ReadOnlyMode();
   public static SystemMode ReadWrite = new ReadWriteMode();

   internal abstract void Save();
   internal abstract SystemDocument Read();

   private class ReadOnlyMode : SystemMode
   {
      internal override void Save() {...}
      internal override SystemDocument Read() {...}
   }

   private class ReadWriteMode : SystemMode
   {
      internal override void Save() {...}
      internal override SystemDocument Read() {...}
   }
}


TheSystem.Mode = SystemMode.ReadOnly;

I don't think just having an IsMatch static method warrants not using simple enums. Something very similar could be achieved with extension methods in this case.

Eli Algranti
  • 8,707
  • 2
  • 42
  • 50
  • So they're a well-known tool that has its uses, but shouldn't be used everywhere. Like most things. Thanks for the examples. – Chris Williams May 12 '13 at 13:50
3

Enums are great for lightweight state information. For example, your color enum (excluding blue) would be good for querying the state of a traffic light. The true color along with the whole concept of color and all its baggage (alpha, color space, etc) don't matter, just which state is the light in. Also, changing your enum a little to represent the state of the traffic light:

[Flags()]
public enum LightColors
{
    unknown = 0,
    red = 1,
    yellow = 2,
    green = 4,
    green_arrow = 8
}

The current light state could be set as:

LightColors c = LightColors.red | LightColors.green_arrow;

And queried as:

if ((c & LightColors.red) == LightColors.red)
    {
        //Don't drive
    }
    else if ((c & LightColors.green_arrow) == LightColors.green_arrow)
    {
        //Turn
    }

Static class color members would be able to support this multiple state without extra functionality.

However, static class members are wonderful for commonly used objects. The System.Drawing.Color members are great examples as they represent a known-name colors that have obscure constructors (unless you know your hex colors). If they were implemented as enums you would have to do something like this every time you wanted to use the value as a color:

colors c = colors.red;
        switch (c)
        {
            case colors.red:
                return System.Drawing.Color.FromArgb(255, 0, 0);
                break;
            case colors.green:
                return System.Drawing.Color.FromArgb(0,255,0);
                break;
        }

So if you've got an enum and find that your constantly doing a switch/case/if/else/whatever to derive an object, you might want to use static class members. If you're only querying the state of something, I'd stick with enums. Also, if you have to pass data around in an unsafe fashion enums will probably survive better than a serialized version of your object.

reference form a old post from this forum : When to use enums, and when to replace them with a class with static members?

Community
  • 1
  • 1
hm1984ir
  • 554
  • 3
  • 7