Enumerations are a very handy programming construct. Especially when you're developing in a larger team, you can
prevent a lot of problems and possible bugs by using enum types for properties that can just have certain values. Take
for instance a class property "Status". It could have several different values: just "open" and "closed" or "O" and "C"
or "M" for modified and "C" for complete etc...If another developer in the team is using your class he always will have
to directly go to your class in order to check the specifications (since also useful intellisense comments are missing
;) ). But if you would use enumerations he can just type and will immediately see a list of possible values. Moreover
you prevent stupid bugs such as (if "C" and "M" would be the correct values) that he assigns "c" and "m" where you can
sure that at some point in your app there will be a wrong comparison.
The problem however in C# is that you
cannot have string enumerations although often they would be handy. I recently had the case where a possible DB value
for a property is "C" for complete and "M" for modified. Furthermore these values have also to be written to a CSV
file. Here a string enumeration would be great, wouldn't it? Of course you could argue to just use constant string
fields, but that wouldn't be so elegant. So I decided to create one.
I searched on the web and found
this
solution which I've taken in part and modified to make it a bit more convenient (at least from my point of view).
The strategy in this example is to make use of the System.Attribute to enhance standard enumerations.
using System;
using System.Collections.Generic;
using System.Linq;
using System.Web;
namespace Jsdevlib.Base
{
public class StringValueAttribute : System.Attribute
{
public StringValueAttribute(string value)
{
_Value = value;
}
private string _Value;
public string Value
{
get
{
return _Value;
}
}
}
}
Then
you can create your string enumeration as needed. For instance
using System;
using System.Collections.Generic;
using System.Linq;
using System.Web;
using Jsdevlib.Base;
namespace SimpleTests
{
public enum StringEnumeration
{
[StringValue("C")]
COMPLETE = 1,
[StringValue("M")]
MODIFIED = 2
}
}
To
now retrieve the defined StringValue, the example on CodeProject used an additional utility class. I preferred to
slightly change this implementation and to use the C# extension methods:
using System;
using System.Collections.Generic;
using System.Linq;
using System.Web;
using System.Reflection;
namespace Jsdevlib.Base
{
public static class StringEnumExtender
{
public static string StringValue(this Enum value)
{
string output = null;
Type type = value.GetType();
FieldInfo fi = type.GetField(value.ToString());
StringValueAttribute[] attrs =
fi.GetCustomAttributes(typeof(StringValueAttribute),
false) as StringValueAttribute[];
if (attrs.Length > 0)
{
output = attrs[0].Value;
}
else
{
throw new InvalidOperationException("The StringValue can just be invoked on String enumerations having the '[StringValue(...)]' attribute.");
}
return output;
}
}
}
To
retrieve the string value you can do now something like
StringEnumeration.COMPLETE.StringValue();
But pay attention that you have to first import
the namespace in which you have definde your StringEnumExtender, because otherwise you won't see the StringValue()
method. That's the drawback of extension methods.
This kind of mechanism gives you great flexibility since you can
add the StringValue attribute to whatever enumeration. Btw, invoking the StringValue() on enumerations that don't
define a StringValue attribute an exception will be thrown. I found that the most reasonable behavior.
Questions? Thoughts? Hit me up
on Twitter