public abstract class Enumeration<T> where T : Enumeration<T> { protected static int nextOrdinal = 0; protected static readonly Dictionary<int, Enumeration<T>> byOrdinal = new Dictionary<int, Enumeration<T>>(); protected static readonly Dictionary<string, Enumeration<T>> byName = new Dictionary<string, Enumeration<T>>(); protected readonly string name; protected readonly int ordinal; protected Enumeration(string name) : this (name, nextOrdinal) { } protected Enumeration(string name, int ordinal) { this.name = name; this.ordinal = ordinal; nextOrdinal = ordinal + 1; byOrdinal.Add(ordinal, this); byName.Add(name, this); } public override string ToString() { return name; } public string Name { get { return name; } } public static explicit operator int(Enumeration<T> obj) { return obj.ordinal; } public int Ordinal { get { return ordinal; } } } public abstract class Enumeration<T> { protected static int nextOrdinal = 0; protected static readonly Dictionary<int, Enumeration<T>> byOrdinal = new Dictionary<int, Enumeration<T>>(); protected static readonly Dictionary<string, Enumeration<T>> byName = new Dictionary<string, Enumeration<T>>(); protected readonly string name; protected readonly int ordinal; protected Enumeration(string name) : this (name, nextOrdinal) { } protected Enumeration(string name, int ordinal) { this.name = name; this.ordinal = ordinal; nextOrdinal = ordinal + 1; byOrdinal.Add(ordinal, this); byName.Add(name, this); } public override string ToString() { return name; } public string Name { get { return name; } } public static explicit operator int(Enumeration<T> obj) { return obj.ordinal; } public int Ordinal { get { return ordinal; } } } public abstract class Enumeration<T> where T : Enumeration<T> { protected static int nextOrdinal = 0; protected static readonly Dictionary<int, Enumeration<T>> byOrdinal = new Dictionary<int, Enumeration<T>>(); protected static readonly Dictionary<string, Enumeration<T>> byName = new Dictionary<string, Enumeration<T>>(); protected readonly string name; protected readonly int ordinal; protected Enumeration(string name) : this (name, nextOrdinal) { } protected Enumeration(string name, int ordinal) { this.name = name; this.ordinal = ordinal; nextOrdinal = ordinal + 1; byOrdinal.Add(ordinal, this); byName.Add(name, this); } public override string ToString() { return name; } public string Name { get { return name; } } public static explicit operator int(Enumeration<T> obj) { return obj.ordinal; } public int Ordinal { get { return ordinal; } } } Here's another interesting idea which caters for the custom behaviour available in Java. I came up with the following Enumeration base class:
public abstract class Enumeration<T> { protected static int nextOrdinal = 0; protected static readonly Dictionary<int, Enumeration<T>> byOrdinal = new Dictionary<int, Enumeration<T>>(); protected static readonly Dictionary<string, Enumeration<T>> byName = new Dictionary<string, Enumeration<T>>(); protected readonly string name; protected readonly int ordinal; protected Enumeration(string name) : this (name, nextOrdinal) { } protected Enumeration(string name, int ordinal) { this.name = name; this.ordinal = ordinal; nextOrdinal = ordinal + 1; byOrdinal.Add(ordinal, this); byName.Add(name, this); } public override string ToString() { return name; } public string Name { get { return name; } } public static explicit operator int(Enumeration<T> obj) { return obj.ordinal; } public int Ordinal { get { return ordinal; } } } It's got a type parameter basically just so the ordinal count will work properly across different derived enumerations. Jon Skeet's Operator example from his answer to another question (What's the equivalent of Java's enum in C#?) above then becomes:
public class Operator : Enumeration<Operator> { public static readonly Operator Plus = new Operator("Plus", (x, y) => x + y); public static readonly Operator Minus = new Operator("Minus", (x, y) => x - y); public static readonly Operator Times = new Operator("Times", (x, y) => x * y); public static readonly Operator Divide = new Operator("Divide", (x, y) => x / y); private readonly Func<int, int, int> op; // Prevent other top-level types from instantiating private Operator(string name, Func<int, int, int> op) :base (name) { this.op = op; } public int Execute(int left, int right) { return op(left, right); } } This gives a few advantages.
- Ordinal support
- Conversion to
stringandintwhich makes switch statements feasible - GetType() will give the same result for each of the values of a derived Enumeration type.
- The Static methods from
System.Enumcan be added to the base Enumeration class to allow the same functionality.
default