When to Use Enums, and When to Replace Them with a Class with Static Members

When to use enums, and when to replace them with a class with static members?

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.

Edit:
@stakx, I think you stumbled on something important, too in response to @Anton's post and that is complexity or more importantly, who is it complex for?

From a consumer's standpoint, I would immensely prefer System.Drawing.Color static class members over having to write all of that. From a producer's standpoint, however, it would be a pain to have to write all of that. So if other people are going to be using your code you might be saving them a lot of trouble by using static class members even though it might take you 10 times as long to write/test/debug. However, if its just you you might find it easier to just use enums and cast/convert as needed.

What's the advantage of a Java enum versus a class with public static final fields?

Technically one could indeed view enums as a class with a bunch of typed constants, and this is in fact how enum constants are implemented internally. Using an enum however gives you useful methods (Enum javadoc) that you would otherwise have to implement yourself, such as Enum.valueOf.

Should static variables be replaced with enums?

Enums are typed.

That is, if you have a method where you have to pass a certain 'state' to a method for instance, you can only pass 'valid' arguments.
For instance:

enum OrderState 
{
pending = 1,
shipped = 2
}

public IList<Order> GetOrdersInState( OrderState )
{
}

This is a good example -imho- of using enums.
When OrderState is an int for which you create 2 const ints, you have no restriction and are able to pass invalid values. The compiler won't complain.

However, the case that you're bringing up, I think using enums is not a valid solution. It's a misuse of using an int, and a const int should be used.

Enums are good, but they should be used where they must be used. They're not the preferred tool in every situation.
Having a const or static var is in this case not an antipattern.

C++ declaring static enum vs enum in a class

static cannot be applied to enum declarations, so your code is invalid.

From N3337, §7.1.1/5 [dcl.stc]

The static specifier can be applied only to names of variables and functions and to anonymous unions ...

An enum declaration is none of those.

You can create an instance of the enum and make that static if you want.

class Example
{
enum Items{ desk = 0, chair, monitor };
static Items items; // this is legal
};

In this case items is just like any other static data member.


This is an MSVC bug; from the linked bug report it seems the compiler will allow both static and register storage specifiers on enum declarations. The bug has been closed as fixed, so maybe the fix will be available in VS2015.

Static enum vs. Non-static enum

All enums are effectively static. If you have a nested enum, it is much the same as a static class.

All classes are lazily loaded (enums or otherwise) however when they are loaded they are loaded all at once. i.e. you can't have a few constants loaded but not others (except in the middle of class initialization)

Java allows certain modifiers to be implicit to avoid having to declare them all the time. This means that adding a modifier doesn't necessarily do anything other than provide a longer way of writing the same thing.

Default modifiers for

class field/method/nested class - package local, non-final, non-static

enum and nested enum - package local, final and static

interface field - public static final

interface method - public abstract

nested class in an interface - public static, non-final

Note: while static is optional for an enum it is always static. However, final cannot be set for an enum even though it is always notionally final (Technically you can have subclasses with overridden implementations for constants)

EDIT: The only place you need to use static with enum is with import static of an enum's value. Thank you @man910

Enum VS Static Class (Normal and With String Values)

From Enumeration Types (C# Programming Guide):

An enumeration type (also named an enumeration or an enum) provides an
efficient way to define a set of named integral constants that may be
assigned to a variable.

The following are advantages of using an enum instead of a numeric
type:

  1. You clearly specify for client code which values are valid for the variable.

  2. In Visual Studio, IntelliSense lists the defined values.

So if you pass enum, it is strongly typed, so you automatically get control over what you can pass into a method.

ScreenSizeEnum size = ScreenSizeEnum.Medium;
SetScreenSize(size);

When using const or static fields you definetely need to check whether the passed int value is taken from the expected diapason.

int somevalue = ...;//anything
SetScreenSize(somevalue); //compiles

private void SetScreenSize(int Screen)
{
switch (Screen)
{
case ScreenSizeClass.Large:
//Do Logic
break;
case ScreenSizeClass.Small:
//Do Logic
break;
default:
// something else, what to do??
break;
}
}

Based on comments:

If it's necessary to check, whether some int is defined in enum, one can do something like this:

int somevallue = 0;
if(Enum.IsDefined(typeof(ScreenSizeEnum), somevallue))
{
//it's ok
}

Or an extension method:

public static T GetEnumValue<T>(this string value) where T : struct
{
Type t = typeof(T);
if (!t.IsEnum)
throw new Exception("T must be an enum");
else
{
T result;
if (Enum.TryParse<T>(value, out result))
return result;
else
return default(T);
}
}

which could be used

int somevalue = 1;
ScreenSizeEnum size = somevalue.GetEnumValue<ScreenSizeEnum>();

As for the string (based on OP's edited question):

From enum (C# Reference):

The approved types for an enum are byte, sbyte, short, ushort, int,
uint, long, or ulong.

So you cannot have an enum of strings. But you can use names from enums, as ToString method returns the name, not the value of the enum.

ScreenSizeEnum.Small.ToString(); //Small

So you can have another extension method on strings:

public static T GetEnumValue<T>(this string value) where T : struct
{
Type t = typeof(T);
if (!t.IsEnum)
throw new Exception("T must be an enum");
else
{
if (Enum.IsDefined(t, value))
return (T)Enum.Parse(t, value);
else
return default(T);
}
}

So that

int i = (int)ScreenSizeEnum.Small;
string str = ScreenSizeEnum.Small.ToString();
ScreenSizeEnum isize = i.GetEnumValue<ScreenSizeEnum>();//ScreenSizeEnum.Small
ScreenSizeEnum strsize = str.GetEnumValue<ScreenSizeEnum>();//ScreenSizeEnum.Small

Is this a correct way to use Enum?

The key point is more on "how will that information be used at runtime". You see, if you starting thinking about writing code such as

switch(someEnum) {
case DO_THIS: ...
case DO_THAT:

... then you are already going into the wrong direction!

The point is: very often think that enums (or their even-more-low-level numeric constant cousins) are a good way to express such designs.

But that actually leads to quite some problems. Very often, the better, "more OO" way of thing is to use some abstract base class with specific subclasses; in other words: polymorphism!

Edit: just to make that more clear ... a "single" switch over an enum isn't really a problem. But far too often, people end up with many many places in code where they switch over their enums. And all of those places might need updates when you create additional enum constants. A coworker of mine calls that the "enum trap".

Why use Enums instead of Constants? Which is better in terms of software design and readability

Suppose you use constant strings (or int values - the same goes for them):

// Constants for player types
public static final String ARCHER = "Archer";
public static final String WARRIOR = "Warrior";

// Constants for genders
public static final String MALE = "Male";
public static final String FEMALE = "Female";

then you end up not really knowing the type of your data - leading to potentially incorrect code:

String playerType = Constants.MALE;

If you use enums, that would end up as:

// Compile-time error - incompatible types!
PlayerType playerType = Gender.MALE;

Likewise, enums give a restricted set of values:

String playerType = "Fred"; // Hang on, that's not one we know about...

vs

PlayerType playerType = "Fred"; // Nope, that doesn't work. Bang!

Additionally, enums in Java can have more information associated with them, and can also have behaviour. Much better all round.

Enum vs Constants/Class with Static Members?

Static members of type int seems to be inferior to an enum to me. You lose the typesafety of an enum. And when debugging you don't see the symbolic name but just a number.

On the other hand if an entry consists of more than just a name/integervalue pair a class can be a good idea. But then the fields should be of that class and not int. Something like:

class MyFakeEnum
{
public static readonly MyFakeEnum Value1=new MyFakeEnum(...);
}

When and how should I use enumeration classes rather than enums?

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.



Related Topics



Leave a reply



Submit