views:

1838

answers:

10
+12  Q: 

C# Enum values

I have a enum containing the following (for example):

UnitedKingdom, UnitedStates, France, Portugal

In my code I use Country.UnitedKingdom but I want to have the value be UK if I assign it to a string for example.

Is this possible?

+29  A: 
Jon Skeet
Ahem, could always change the names of the enum values to their string representatives, if you don't mind breaking some style rules!
Ed Woodcock
Unfortunately, Dictionary<Enum, T> would perform horribly: http://www.codeproject.com/KB/cs/EnumComparer.aspx
hmemcpy
@hmemcpy hmm, always thought it'd perform basically like a Dictionary<int, x>, given that an enum is effectively a set of int defined as names, hence why you can do enum i = {j =0, b=7} or whatever
Ed Woodcock
I would only worry about this when I saw some actual evidence that it was causing a bottleneck. As ever, use the simplest code that works until you have a good reason to do anything else. To my mind, there's a big difference between "would perform horribly" and "wouldn't perform optimally".
Jon Skeet
@Ed Woodcock Integers implement IEquatable, and the EqualityComparer which is used by the Dictionary handles that special case. Ayende (author of Rhino Mocks) wrote about it: http://ayende.com/Blog/archive/2009/02/21/dictionaryltenumtgt-puzzler.aspx
hmemcpy
@Jon: I would like to point out the risk that people run when they wait to see something that can be simply changed to perform better (and still read clean) up front but will require a pretty major rewrite after the app is in production. If I was going to shove millions of rows though this I would probably use a factory method wtih a switch. But it would work either way. (And Jon's way is easier to extend later)
Matthew Whited
Why would it require a big rewrite to fix the performance after the app is in production? It would just mean changing the implementation of the extension method. Anyway, I've edited the answer a bit since you wrote that comment - more comments welcome!
Jon Skeet
It would depend on how people write the code around it. Many people probably would not use an extension method to extract the string. Some (probably most) would just use the indexer of the dictionary to retrieve the string. And in cases like that it could be difficult to change the code later. (I'm not talking about the well formed and abstracted apps... I'm talking about the fun ones that we all try to avoid maintaining)
Matthew Whited
The dictionary would have to be publicly visible for that to be an issue though - it would be *very* simple to make it private to the class containing the extension method.
Jon Skeet
Downvoters: care to give a reason why?
Jon Skeet
I'll second that Jon - downvotes without a comment explaining why don't help anyone out
Scott Ivey
+6  A: 

Pseudo code:

enum MyCountryEnum
{
    UnitedKingdom = 0,
    UnitedStates = 1,
    France = 2,
    Portugal = 3,
}

string[] shortCodes = new string[] {"UK", "US", "FR", "PO"};


MyCountryEnum enumValue = MyCountryEnum.UnitedKingdom;
string code = shortCodes[enumValue];
rein
The maintenance overhead of this is worrisome. Keeping two unconnected data structures synchronized is always a red flag.
Rex M
+14  A: 

You could create an extension method public static string ToShortString(this Country country). In the method you could use either a static Dictionary as Jon suggests, or you could simply do a switch case.

Example:

public static class CountryExtensions
{
    public static string ToShortString( this Country target )
    {
     switch (target) {
      case Country.UnitedKingdom:
       return "UK";
      case Country.UnitedStates:
       return "US";
      case Country.France:
       return "FR";
      case Country.Portugal:
       return "PT";
      default:
       return "None";
     }
    }
}
Timothy Carter
With only 4 values, I vote for the switch statement. Refactor to dictionary if and when the switch statement becomes more cumbersome than the dictionary implementation.
tvanfosson
Hope you don't mind that I added an example.
tvanfosson
Yeah agree with only 4 switch case would be the right choice. And thanks for adding the code, I hadn't gotten around to it yet.
Timothy Carter
+1 but bear in mind there are a slightly larger number of countries that the 4 listed =]
Ed Woodcock
+2  A: 

Just use the DescriptionAttribute

No need to create a dictionary if you only need to get a String representation for your enum values. See this example

[EDIT] Oh ... forgot to mention that it is more reusable than dictionaries, since you only need one common util class to help with getting the description and then all you need to do is add the DescriptionAttribute next time you add an enum value or you create a new enum with the same requirements. In the dictionary/switch solution, it is harder to maintain and it gets messy once you have many enum types.

Rado
Indeed, that was the other alternative I mentioned. However, it's more code and it uses reflection (which I generally try to avoid unless I really need it). Of course there's nothing magically about DescriptionAttribute - you could create your own attribute and use that instead.
Jon Skeet
A: 
var codes = new Dictionary<Country, string>() 
        { { Country.UnitedKingdom, "UK" },
        { Country.UnitedStates, "US" },
        { Country.France, "FR" } };
Console.WriteLine(codes[Country.UnitedStates]);
BlackTigerX
+15  A: 

I prefer to use the DescriptionAttribute on my enums. Then, you can use the following code to grab that description from the enum.

enum MyCountryEnum
{    
    [Description("UK")]
    UnitedKingdom = 0,    

    [Description("US")]
    UnitedStates = 1,    

    [Description("FR")]
    France = 2,    

    [Description("PO")]
    Portugal = 3
}

public static string GetDescription(this Enum value)
{
    var type = value.GetType();

    var fi = type.GetField(value.ToString());

    var descriptions = fi.GetCustomAttributes(typeof(DescriptionAttribute), false) as DescriptionAttribute[];

    return descriptions.Length > 0 ? descriptions[0].Description : value.ToString();
}

public static SortedDictionary<string, T> GetBoundEnum<T>() where T : struct, IConvertible
{
    // validate.
    if (!typeof(T).IsEnum)
    {
        throw new ArgumentException("T must be an Enum type.");
    }

    var results = new SortedDictionary<string, T>();

    FieldInfo[] fieldInfos = typeof(T).GetFields();

    foreach (var fi in fieldInfos)
    {

        var value = (T)fi.GetValue(fi);
        var description = GetDescription((Enum)fi.GetValue(fi));

        if (!results.ContainsKey(description))
        {
            results.Add(description, value);
        }
    }
}

And then to get my bound enum list, its simply a call to

GetBoundEnum<MyCountryEnum>()

To get a single enum's description, you'd just use the extension method like this

string whatever = MyCountryEnum.UnitedKingdom.GetDescription();
Scott Ivey
+1  A: 

Whenever I see an enum I feel that the code should be refactored. Why not make a Country class and add methods to do some of the obstacles you are trying to get around. Assigning values to an enum is an even bigger code smell.

Why the downvotes? I think it is pretty widely accepted that using a polymorphic approach is better than using an enum. There is zero reason to use an enum when you can use the ValueObject design instead.

Here is a good blog post on the topic: http://devpinoy.org/blogs/cruizer/archive/2007/09/12/enums-are-evil.aspx

Bryan Rowe
I would agree that in almost all cases when someone is using an Enum, they should probably do a double take at their code to see if an Object might be a better option.
Dan
This is by far the cleanest way to do things. I'm surprised you didn't get more upvotes.
Kramii
A: 
Klinger
While this would work. You will probably want to be explicit on the values instead of letting the compiler add them for you.
Matthew Whited
Good point Matthew. I have updated my answer.
Klinger
+3  A: 

One other possibility that hasn't been mentioned is something like this:

public class Country
{
    public static readonly Country UnitedKingdom = new Country("UK");
    public static readonly Country UnitedStates = new Country("US");
    public static readonly Country France = new Country("FR");
    public static readonly Country Protugal = new Country("PT");

    private Country(string shortName)
    {
        ShortName = shortName;
    }

    public string ShortName { get; private set; }
}

From this point you could add more properties, but beware of how much you add to the class, and how many static members you add, as the memory bloat it adds could make it not worth it.

I don't think there are many cases where this strategy is the best approach, but it is an option to be aware of when attempting to add properties or attributes to something you want to be able to treat as essentially an enum.

Timothy Carter
If you are concered about memory usage of your static objects you could make them static readonly properties and use Weak References.http://msdn.microsoft.com/en-us/library/ms404247.aspx
Matthew Whited
@Matthew Whited: can you provide an example of how to use Weak References in this case?
rohancragg
+2  A: 

I had to leave my work on this project for a while, and having come back to it, I had a moment of inspiration.

Rather than an enum, I created a new class like so:

public class Country
{
    public const string UnitedKingdom = "UK";
    public const string France = "F";
}

This way I can use Country.UnitedKingdom in my code and the value "UK" will be used.

I'm just posting this answer as an alternative solution.

Neil

neildeadman