C# – Overloading an Enum’s ToString()
Enumerations can sometimes be useful. It’s true, I think that you can refactor enum’s into big-I-Interfaces a lot of the time, but enums do have their place. There are 2 things that I don’t like about enums, however:
- They eventually lead to lots of if-this-than-that-else-blah-otherwise-holycrap conditional hell (hence refactoring into big-I-Interfaces), and
- You can’t overload the ToString() method
If you’re stuck using an enum, point 2) can become pretty valuable. For example, in my current case, I have an enumeration that denotes the different styles available to an image. These styles are only accessed at runtime, and can be mixed and matched using bitwise operations. Eventually, these styles get rendered from an enum into a string stored in an XML file — it is here where overloading the enum’s ToString() method would come in handy. Unfortunately, out of the box, all you’re capable of doing is a .ToString() on the enum, which will render several different possibilities depending on how you defined your enum. Fortunately C#’s extension methods and Custom Attributes allow us to get around all that.
The solution I came to was to create a Custom Attribute which would decorate each enum value. This custom attribute (called EnumDescription) has a single property called “Text” which will be used via some magical extension methods.
public class EnumDescription : Attribute
{
public string Text
{
get { return _text; }
} private string _text;
public EnumDescription(string text)
{
_text = text;
}
}
Pretty simple. I then decorate my enum values with the EnumDescription attribute, and provide whatever description I want. In our case, I’ll just create a simple RGB enum with english constant names, but french descriptions (cause, you know, I’m cultured like yogurt).
[Flags]
public enum RGB
{
[EnumDescription("rouge")]
Red = 0,
[EnumDescription("vert")]
Green = 1,
[EnumDescription("bleu")]
Blue = 2
}
The last component of this excercise is to create an extension method that allows us to easily use the EnumDescription attribute without having to write reflection lines whenever we need. The beauty of creating an extension method for this is that the enumeration will get intellisensed with our extension method and the developer won’t need to know of some obscure static method on some static class.
public static class EnumExtensions
{
public static string ToDescription(this Enum enumeration)
{
Type type = enumeration.GetType();
MemberInfo[] memInfo = type.GetMember(enumeration.ToString());
if (null != memInfo && memInfo.Length > 0)
{
object[] attrs = memInfo[0].GetCustomAttributes(typeof(EnumDescription), false);
if (null != attrs && attrs.Length > 0)
return ((EnumDescription) attrs[0]).Text;
}
return enumeration.ToString();
}
}
In the method above we check to see if the enumeration in question is decorated with an EnumDescription custom attribute. If it is than we use the Text description contained within that attribute, otherwise we’ll fall back on whatever .ToString() returns.
In the end, from the point of view of the developer consuming the API, this is what it looks like:

Of course, the last thing we need to do is to create an extension method that uses the EnumDescription in the opposite direction (similar to Enum.Parse), but considering I don’t actually need that code just yet, I haven’t written it. Next time!
Or, if you don’t want to wait, impress me by applying for 1 of our jobs, and submit your answer as part of your application!
on May 7, 2008 on 3:45 am
Why not use generics to do this heavy lifting? I think it would be faster, easier and more extensible.
The problem with what you are doing here is confusing the enumeration of types to its implementation. The ‘ToString’ of ‘rouge’ is only important in only one context while RBG.Red is useful in all contexts. What you need is a class FrenchColour
Just my two cents.
on May 7, 2008 on 5:21 am
Oh, I agree whole heartedly, actually. You’re bang on. The example above was just an illustration – depending on the context of what you’re doing there are far better things that can be done. In my real world case, I simply wanted to “serialize” (for lack of a better term) a specific value (or set of values) out to an XML file.
For what I’m doing right now it’s fine, however once one starts looking into issues such as localization or encapsulating a richer set of functionality, then a simple enumeration will cease to be adequate. Truth be told, we needed to do something now instead of later, and this enumeration was the most elegant solution my coworker and I could figure out without having to refactor classes.
I’m all for constantly improving and refactoring code base, but not when it’s at the tail end of an iteration and the code-to-be-refactored in question was designed and written by a guy that’s going to Nepal for a month! In due time I would imagine the Enumeration going the way of the do-do, sure enough.
It was a pleasant surprise reading a comment from you Mr. Bendell. When will we have these discussions in person?
on May 7, 2008 on 5:39 pm
Serialization is still very context specific and very similar to localization. But I do understand your issue with time pressures.
Of course a better solution is to use an XmlSerializationFactory where you register a decoding/encoding codec that can handle generic objects. Then when you pass in an object or input stream the appropriate codec is executed. So in your example the pseudo code would look something like this:
Console.Writeln(XmlSerialization.encode(RGB.Red));
If this is something you want to revisit in the furture, you should write a test case that fails or at least issues a warning so you make sure you can refactor the code.
Again, just my two cents. Take it for what its worth considering I haven’t been coding for the last 12 months
Not sure if we’ll be heading to SK anytime soon. It all depends on what happens in the next few days. We might come out for a wedding at the end of aug, but we’ll see.
on May 7, 2008 on 9:27 pm
All very good things, I’ve no further followup other than I will definitely keep your suggestions in mind when it comes to our cleanup iteration.
Next time you swing by SK lemme know. I’ll swing up to saskatoon and we can have a lunch at Amigo’s and get delightfully full on saskatoon’s finest mexican bar cuisine.
on June 25, 2008 on 11:36 pm
This got me thinking, how about a solution where I specify a resource file containing the strings for the descriptions ? This way you can truely make a localized representation of enum values
on June 26, 2008 on 8:23 am
It’s a good idea Willemm, and if I could I certainly would. Unfortunately, C# requires that arguments provided to a custom attribute be a const, so I don’t believe that a localized string (via resources) would work (just a hunch, however – caveat being I didn’t try it).
Thanks for reading and leaving a comment! Always welcomed!
on May 28, 2009 on 1:07 am
Yes, you can… if you use some imagination.
The string you supply in the attribute should not be the actual description. If you make the string value the “key” that you use to store the value in the resource file, then your code can lookup the current culture and pull the value from the resource file related to the appropriate culture.
You are only one step away.
Maybe this will get you started:
///
/// Provides access to localized text resources where the string
/// provided is the name or key to the text contained in the
/// resource file(s).
///
[Serializable]
public sealed class LocalizedDescriptionAttribute : DescriptionAttribute {
///
/// Initializes a new instance of the class.
///
/// The description text which refers to the name
/// of the string in the resource file.
public LocalizedDescriptionAttribute(string description)
: base(description) {
if (!(description != null && description.Length > 0))
throw new InvalidOperationException(Resources.Exception_AttributeDescriptionCannotBeNullOrEmpty);
}
///
/// Provides a LocalizedDescriptionAttribute description.
///
/// The string identifying the resource file.
/// NSurePro.Domain.Properties.Resources
///
/// Returns the localized string/ value description from the resource file.
///
public string LocalDescription(string resourceFile, CultureInfo cultureInfo) {
ResourceManager resourceManager = new ResourceManager(resourceFile, Assembly.GetExecutingAssembly());
string result = String.Empty;
try {
result = resourceManager.GetString(base.Description, cultureInfo);
} catch {
// nothing
}
return (result == null || result.Length <= 0) ? base.Description : result;
}
}
on May 28, 2009 on 1:08 am
I didn’t post that code more than once, this website auto-posted on me and just tweaked… sorry