views:

246

answers:

4

There has been a lot of talk of Enums in general violating Clean Code-principles, so I'm looking for people's favorite Enum anti-patterns and alternative solutions for these.

For example I've seen code like this:

switch(enumValue) {
    case myEnum.Value1:
        // ...
        break;
    case myEnum.Value2:
        // ...
        break;
}

It's one step better than switch-statements with magic strings, but this probably could have been solved better with a factory, a container or other pattern.

Or even old-school code like this:

if(enumValue == myEnum.Value1) {
   // ...
} else if (enumValue == myEnum.Value2) {
   // ...
}

What other anti-patterns and better implementations have you experienced with enums?

A: 

Using enums in not anti-pattern. In some books about refactoring this code is used to demonstrate how to replace it with polymorphism. It would be OK when you overuse enums in code.

Arseny
That was not what was said. I asked for anti-patterns involving enums.
Seb Nilsson
+1  A: 

I see having two switch statements as a symptom of non-OO design as explained further in this answer.

ChrisW
A: 

You have this situation:

switch(enumValue) {
    case myEnum.Value1:
        Action1();
        break;
    case myEnum.Value2:
        Action2()
        break;
}

You can do this:

public class ValueBase
{
   public virtual void Action()
   {
      //default implementation
   }
}

class Value1 : ValueBase
{
   public override void Action(){}
}

class Value2 : ValueBase
{
   public override void Action(){}
}

Now call you can define an object of a specific type to call the related action, your action defines a manner and it can be a class instead of an enum.

Sample Usage:

class Logger
{
  virtual void Create();
 virtual void Log(...);
}

class FileLogger : Logger
{
  void Create();
  void Log(...);
}

class DBLogger : Logger
{
  void Create();
  void Log(...);
}

....
Class MyClass
{
Logger currentLogger = null;
MyClass(Logger currentLogger)
{
  logger = currentLogger;
}
public void LogMessage(string str)
{
  logger.Log(str);
}
}

.....
class SampleCalss1
{
....
void Event()
{
  FileLogger logger = new FileLogger();
  MyClass mc = new MyClass(logger);
  mc.LogMessage("dsds");
}
}

class SampleClass2
{
void AnotherEvent()
{
  DBLogger logger = new DBLogger();
  MyClass mc = new MyClass(logger);
  mc.LogMessage("dsds");
}
}

}

SaeedAlg
You're still going to need a switch somewhere to decide on the type of class to instantiate?
Paddy
no when u calling the main function u have a specific class ur main function input parameter is ValueBase type, and u just call the action, now u used polimorfism in OO to call the related Action, u have an implicit call to related action.
SaeedAlg
+2  A: 

I think Enums are quite useful. I've written a few extensions for Enum that have added even more value to its use

First, there's the Description extension method

public static class EnumExtensions
{
    public static string Description(this Enum value)
    {
        var entries = value.ToString().Split(ENUM_SEPERATOR_CHARACTER);
        var description = new string[entries.Length];
        for (var i = 0; i < entries.Length; i++)
        {
            var fieldInfo = value.GetType().GetField(entries[i].Trim());
            var attributes = (DescriptionAttribute[])fieldInfo.GetCustomAttributes(typeof(DescriptionAttribute), false);
            description[i] = (attributes.Length > 0) ? attributes[0].Description : entries[i].Trim();
        }
        return String.Join(", ", description);
    }
    private const char ENUM_SEPERATOR_CHARACTER = ',';
}

This will allow me to define en enum like this:

 public enum MeasurementUnitType
 {
    [Description("px")]
    Pixels = 0,
    [Description("em")]
    Em = 1,
    [Description("%")]
    Percent = 2,
    [Description("pt")]
    Points = 3
 }

And get the label by doing this: var myLabel = rectangle.widthunit.Description() (eliminating any need for a switch statement).

This will btw return "px" if rectangle.widthunit = MeasurementUnitType.Pixels or it will return "px,em" if rectangle.widthunit = MeasurementUnitType.Pixels | MeasurementUnitType.Em.

Then, there is a

    public static IEnumerable<int> GetIntBasedEnumMembers(Type @enum)
    {
        foreach (FieldInfo fi in @enum.GetFields(BindingFlags.Public | BindingFlags.Static))
            yield return (int)fi.GetRawConstantValue();
    }

Which will let me traverse any enum with int based values and return the int values themselves.

I find these to be very useful in an allready useful concept.

danijels
We not doing it with shorter and simpler code with a Dictionary<TEnum, TDescString>? What value does above code bring?
Seb Nilsson
@Seb: Several reasons: first, the description is next to the declaration as opposed to somewhere else if you use a Dictionary. Secondly, the description is always present with the enum type, which leads to...finally, the type can be imported into another assembly and the enum values and their descriptions can be reflected and presented to the user (useful for editors and is somehting I've done).
Skizz
Thanks Skizz, for saving me the time ;) Well done.
danijels
@Skizz Very good points. It's all philosophical. One could say another assembly would not know about the attribute, but they could look up a dictionary. And if they belong together, maybe the enum and lookup-method should be wrapped by a common class. But again, all valid points, thanks.
Seb Nilsson