Dear reader of Juri's TechBlog,
I moved my blog to a new domain and a new hosting solution as well. I'm now blogging on juristr.com.

String enumerations in C#

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.

Posts you might also be interested in..

Credits: Hoctro | Jack Book

4 Comments:

Peter Gfader said...

hm...
you can have string enumerations in C#

just call ToString() on that enum variable

EXAMPLE
enum Colors { Red, Green, Blue, Yellow };
Colors x = Colors.Red;
Console.WriteLine("Color: " + x);
Console.WriteLine("Color: " + Colors.Red);

both return the string instance
WriteLine calls ToString implicit

Juri Strumpflohner said...

Yes I know, that's true. But in that case you'll get basically just the name of the enumeration variable printed out. So the names in my case would be "C" and "M", not really expressive, but yes you could do that.
But if you want to choose more expressive names (which is usually always better, then you have to go for the approach I described.
For your example with the colors, the ToString() is perfectly suited.

Greets to Australia :)

Manfred said...

Hello,
nice post. Thats really a good idea and it would have been help full many times in the past... because I use enumerations in many places.

Juri Strumpflohner said...

Hi,
thanks. Yes I wanted to create such an enumeration already multiple times but then due to time pressure I always just used string constants, which often are also enough.

Post a Comment