Converting Enumerations to User Readable Strings in .NET

Suppose you have the following scenario: You have a function that can return multiple return types codes via an enum value. For each of those enum values, you want to inform the user the result of the operation by some user friendly string.

A common implementation I see is some sort of switch statement that resolves enumerations to a string by way of a switch statement or hash table or something. And whenever that string is needed, call into said method.

And although this is viable, this creates a disconnect between the enum and it’s actual string literal definition. In addition, for each new enumeration value, that giant switch statement needs to be updated with a new string value. If there were only a clean way to map an enum to a string value automatically… and there is! With clever usage of attributes, reflection, and extension methods, one can do something like this:

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Linq.Expressions;

namespace EnumString
{
[AttributeUsage(AttributeTargets.Field)]
class EnumStringAttribute : Attribute
{
string myValue;
public EnumStringAttribute(string value)
{
myValue = value;
}

public override string ToString()
{
return myValue.ToString();
}
}

static class ExtensionMethods
{
public static string ToUserString(this Enum enumeration)
{
var type = enumeration.GetType();
var field = type.GetField(enumeration.ToString());
var enumString = (from attribute in field.GetCustomAttributes(true) where attribute is EnumStringAttribute select attribute).FirstOrDefault();
if (enumString != null)
return enumString.ToString();
return enumeration.ToString();
}
}

enum AuthenticationResult
{
[EnumString("This username is not registered.")]
NotRegistered,
[EnumString("Incorrect password.")]
BadPassword,
[EnumString("Logging in...")]
Success,
}

class Program
{
static void Main(string[] args)
{
Console.WriteLine(AuthenticationResult.BadPassword.ToUserString());
Console.WriteLine(AuthenticationResult.NotRegistered.ToUserString());
Console.WriteLine(AuthenticationResult.Success.ToUserString());
}
}
}

Delaring string values can simply be done inline, and the usage is simple as well! Just call the new extension method to get your user friendly string!

(Of course, for localization, you may want to map the enum to a string resource rather than a hard coded string value; but a similar approach can be used.)

Language Mavens, Tool Mavens

mvn

Recently, a fellow coworker referred me to an article by Oliver Steele about Language Mavens and Tool Mavens. The synopsis is that there are two types of deveopers:

  • Language Mavens are those that leverage a features of the best language to complete the task at hand; the IDEs/tools used do not matter so much.
  • And conversely, Tool Mavens leverage the power of mature, full featured development tools to complete their tasks: an integrated editor, debugger, code refactoring, etc. The language itself does not matter because, it is just the same old set of classes and methods with slightly different names.

Naturally, this led to a bit of introspection, which resulted in the diagram that you can see above: I think I am somewhat between both camps, in that I choose and tend to use a variety of languages on a frequent basis to get my work done. But I find myself more so gravitating towards the languages with the richer tools, because they make suit my programming habits better.

Tools

The tool I require a language to have before I even consider touching it is an integrated debugger. Well, to qualify that statement, I require that for applications with complex execution paths and sustained runtimes. That means for bash, Ruby, Perl, and JavaScript, it doesn’t matter, because printf debugging will suffice. [1] However, if you follow this blog, you may have read about my work on porting Mono to Android. Although Mono has a great integrated x86_64 debugger, none exists for the ARM platform. Doing development using Mono on Android is not really a viable option to me until the debugger exists (or I get around to implementing it myself).

The other tool I prefer a language have is auto complete (aka content assist). It’s purpose is two-fold:

  1. When learning a new language/API/platform, content assist severely lowers the learning curve. Instead of hunting down method signatures, class names, and descriptions on Google, it is built into my editor. This ultimately saves me a significant amount of time.
  2. Eventually, when I master the language, auto complete serves a different purpose: it reduces the amount I need to type by a little under 50%. [0] This is interesting, because a language without code completion would need to be able to complete a task in half the lines over a language that does support it before it actually becomes a more efficient use of my time.

Languages

As Steele’s article states, C# and Visual Studio, as with everything with Microsoft, is an exception to the rule. The new languages (and features) are released at the same time as the tools. And generally, I find myself getting more excited about the languages aspects, than the tools. For example, with VS 2010 (which should be in beta very shortly I hear), we will get: F#, Dynamic Language Runtime (Iron*!), and full expression tree support in C# (to support the DLR and the new dynamic keyword). [2]

Lately, in various projects, I find myself wanting to do more in the way of code generation. Be it code being generated from a model or modifying/creating new code at run time. So that is what spurred my desire to learn Ruby and Python (of which I currently favor Ruby). Though I don’t think this is something I can not live without.

As for language features that are to-die-for, I find it hard to cope without closures and generics, of which Java has neither. [3] The lack of generics is why I also did not really adopt C# over C++ (templates) until version 2.

 

Where do you fall as a language/tool maven, and why?

 

 

 

 

[0] I did this by recording my keystroke count using a free Windows application, and disregarded keystrokes for any navigation or correction keys: backspace, delete, and arrows. Then I compared the results versus the character count of the code written.

[1] Incidentally, I realized I have learned around 5 new languages in the past year. Though I can only claim proficiency in one, the language with the best tools: Java.

[2] Using expression trees in C# to Frankenstein together some new code at runtime seems like there could be infinite Lisp-ish possibilities. Though you can dynamically create new code at runtime using Ruby/JavaScript, you can’t modify or access the expression trees themselves like Lisp. C# doesn’t allow you to look at any expression tree at runtime either, but it does provide language integrated support for building expression trees (and has in a primitive form since C# 3), which can have a similar effect.

[3] Type erasure is not what I would call a real implementation of generics. Anonymous inner classes are not closures.

Gitweb Line Highlighting

codehighlight

I made a few more changes today to support line highlighting of gitweb blobs. Like SyntaxHighlighter, the line highlighting is also completely JavaScript driven. When you highlight a line, it updates the fragment portion of the URL in your browser. Then when you send the URL (with the fragment) to someone, they will see the same highlighted code.

Click here for a sample of code highlighting.

Fun exercise in my quest to catch up and learn JavaScript, CSS, et al.

I couldn’t do this by modifying the query string, because that causes a browser reload when changing window.location. I could perhaps have made a “create hyperlink” button that puts the hyperlink with a modified query string into your paste buffer, but that isn’t as easy as just copying the address out of your browser address bar.

Gitweb Support for SyntaxHighlighter

After getting Gitosis set up on my Hackintosh, I set up gitweb as well. But vanilla gitweb is really ugly; it’s almost as bad as sitting at a console typing the git commands manually. So I spent a good day or so trying to tweak gitweb to work with SyntaxHighlighter. For the longest time, SyntaxHighlighter simply would not work on any page at all. After prodding for a while, I finally figured out that it was due to gitweb.cgi returning the content-type as “application/xhtml+xml” instead of “text/html”.

Click here to see a sample gitweb repository with SyntaxHighlighter enabled. Navigate around the projects, and click any of the language specific blob links (.c, .cs, etc) to see the new highlighting.

// This is SyntaxHighlighter, and
// it now works in gitweb!
if (true)
{
Console.WriteLine("Hooray!");
}

Head over to my GitHub repository to get my git fork with the tweaked gitweb and instructions!

P.S. This was my first time hacking at Perl. I feel violated.

P.P.S. The Perl brush is intentionally disabled. It is a little buggy.