C# enum
s have been bugging me for quite a long time.
Don't get me wrong, I use enum
s wherever I can, but there are some things that the syntax is just too annoying, not to mention the performance penalty of having to use reflection for certain operations like parsing from string
s, or getting all available values.
Searching the web, I found some patterns that addressed the usability and interoperability of Enum
s and other types, but they usually required to write too much code per Enum
because they rely on static code patterns for each enum
type.
As you all probably know, static
classes/code can't use inheritance well. You still have access to protected static
parent members, but you can't use polymorphism to override the base methods. What's more is that polymorphism isn't enough here because inheritance isn’t type-safe enough for the job.
Pondering how to address this issue, I think I've found a good mix of writing as little code as possible on one hand, and gaining the type-safe, readable, interchangeable features similar to enum
, and in the same stroke also gaining usability of a real object type with a way to define customized operators, explicit and implicit conversion methods, value mapping, and anything else you wish to add in functionality.
The hero of the day <dramatic drum rolls>: C# Generics.
C# generics are really versatile, and here they provide the conduit for code reuse, while keeping the enum
types unique.
Let's dive into the code and I'll explain my solution as best as I can.
Please note that the patterns themselves are not of my design, I only came up with the way to write it more reusable using generics.
First, we'll start with an interface declaration (later, I'll explain why):
public interface IEnumBase<E, T> where E: IEnumBase<E, T>{
T Value { get; }
string Name { get; }
}
The trick here is including the IEnumBase
derived class (enum
-type from now on) in the generic template (as type E
), causing the entire hierarchy to be unique to the specific enum
-type.
Now the base code implementation, starting with the class definition and the constructor and interface members implementation:
public abstract class EnumBase<E, T> : IEnumBase<EnumBase<E, T>, T> where E: EnumBase<E, T>
{
#region Instance code
public T Value { get; private set; }
public string Name { get; private set; }
protected EnumBase(string Name, T EnumValue)
{
Value = EnumValue;
this.Name = Name;
mapping.Add(Name, this);
}
public override string ToString() { return Name; }
#endregion
Pretty basic, though you should note that the class is abstract
and the constructor is protected forcing instantiation only via a child-class. Also the mapping.Add
call will be explained further down.
Now comes the 'good stuff', what the generic class is all about – its static
methods and members.
#region Static tools
static private readonly Dictionary<string, EnumBase<E, T>> mapping;static EnumBase()
{
mapping = new Dictionary<string, EnumBase<E, T>>();
}
One feature of native C# enum
s available via reflection is parsing and enumerating, a dictionary
makes this easy and efficient (as I mentioned before, I take no credit for the ideas, I just use them in my own way).
Whenever a new object is constructed, it's added to the mapping Dictionary
, thus populating it automagically.
Now the Parse
method:
protected static E Parse(string name){
EnumBase<E, T> result;
if (mapping.TryGetValue(name, out result))
{
return (E)result;
}
throw new InvalidCastException();
}
Hold on! Why is that method protected
? This means I'll need to write code for the child class! Why!?
Don't get angry, I already told you static
code is problematic to reuse. The reason for defining the Parse
method protected
is to ensure the inheriting class' static
members are initialized when it's called, and we can only do that by forcing the derived class to call from its own static
method.
By writing all the code, all the derived class needs to do is just forward the call to the parent class' method, a single short line of code.
Next the enumeration member (using a bit of LINQ magic):
protected static IEnumerable<E> All
{
get { return mapping.Values.AsEnumerable().Cast<E>(); }
}
Like with the Parse
method, this static
property is also protected
.
So, now that we have an EnumBase
, how do we define a type-safe, versatile enum
-type?
Here is a simple example:
public sealed class YesNoEnum : EnumBase<YesNoEnum, int>
{
public static readonly YesNoEnum Yes = new YesNoEnum(0, "Yes");
public static readonly YesNoEnum No = new YesNoEnum(1, "No");
private YesNoEnum(int value, String name) : base(name, value) { }
public new static IEnumerable<YesNoEnum> All
{
get { return EnumBase<YesNoEnum, int>.All; }
}
public static explicit operator YesNoEnum(string str)
{
return Parse(str);
}
public static implicit operator string(YesNoEnum e)
{
return e.Name;
}
public static implicit operator int(YesNoEnum e)
{ return e.Value; }
}
As you can see, YesNoEnum
, although a bit more complicated in the declaration phase, can now be used easily in your code, where YesNoEnum.Yes
and YesNoEnum.No
are unique type-safe entities member of the YesNoEnum
class, interchangeably as a string
or int
, and we can enumerate through its values.
I still have one thing left to explain, why I based EnumBase<E, T>
on an interface
IEnumBase<E, T>
.
The reason was I wanted an additional implementation where the Value
and Name
properties point to the same string
value. I could have declared it using a string
value but this special case does not require a Dictionary
, a List
will suffice, and there is no need for a pair of string
values in memory, one is enough.
I will not go into the details of this special case implementation, but you can examine it in the complete code available via the link below.
That’s all folks. Now that we have a reusable code base for enum
s, we can expand it in whichever way we want. Do you have any ideas as to what other features would be helpful to add to this base class?
The complete code link can be found at http://pastebin.com/kwD3yjer.