Tuesday, May 3, 2011

Enum ToString

My enum consists of the following values:

private enum PublishStatusses{
 NotCompleted,
 Completed,
 Error
};

I want to be able to output these values in a user friendly way though.
In this SO post, there is a lot of code that I can't seem to compile..
I don't need to be able to go from string to value again.
Why is it not compiling at my machine? How can I get such a result?

From stackoverflow
  • I use the Description attribute from the System.ComponentModel namespace. Simply decorate the enum and then use this code to retrieve it:

    public static string GetDescription<T>(this object enumerationValue)
                where T : struct
            {
                Type type = enumerationValue.GetType();
                if (!type.IsEnum)
                {
                    throw new ArgumentException("EnumerationValue must be of Enum type", "enumerationValue");
                }
    
                //Tries to find a DescriptionAttribute for a potential friendly name
                //for the enum
                MemberInfo[] memberInfo = type.GetMember(enumerationValue.ToString());
                if (memberInfo != null && memberInfo.Length > 0)
                {
                    object[] attrs = memberInfo[0].GetCustomAttributes(typeof(DescriptionAttribute), false);
    
                    if (attrs != null && attrs.Length > 0)
                    {
                        //Pull out the description value
                        return ((DescriptionAttribute)attrs[0]).Description;
                    }
                }
                //If we have no description attribute, just return the ToString of the enum
                return enumerationValue.ToString();
    
            }
    
    borisCallens : Nice, I will put that in my helper lib :) Thx
    Will : Extension methods are quicker to code, use, and support than metadata-based methods.
  • If you want something completely customizable, try out my solution here:

    http://www.kevinwilliampang.com/post/Mapping-Enums-To-Strings-and-Strings-to-Enums-in-NET.aspx

    Basically, the post outlines how to attach Description attributes to each of your enums and provides a generic way to map from enum to description.

  • foreach( PublishStatusses p in Enum.GetValues (typeof(PublishStatusses)) )
    {
       Console.WriteLine (p);
    }
    
    borisCallens : How does that answer my question exactly?
    Frederik Gheysels : It allows you to get all your enum values, and output them. That's what you wanted ?
    borisCallens : "I want to be able to output these values in a user friendly way"
  • That other post is Java. You can't put methods in Enums in C#.

    just do something like this:

    PublishStatusses status = ...
    String s = status.ToString();
    

    If you want to use different display values for your enum values, you could use Attributes and Reflection.

    borisCallens : HA! Silly me. I'm becoming to C#centric lately :P
    annakata : toString is not safe in all cases - an enum with multiple entries with the same value (say for integer enums) will return the key of the first matching value, not the key of the item tested, this is why Enum.GetName is preferred
    Lemmy : Well it was the easiest solution for his specific enum
  • The easiest solution here is to use a custom extension method (in .NET 3.5 at least - you can just convert it into a static helper method for earlier framework versions).

    public static string ToCustomString(this PublishStatusses value)
    {
        switch(value)
        {
            // Return string depending on value.
        }
        return null;
    }
    

    I am assuming here that you want to return something other than the actual name of the enum value (which you can get by simply calling ToString).

    borisCallens : Although valid, I like the attribute way more. That way I can put my toSTring method in a seperate library, whilst putting the custom string representation with the enum itself
    Lemmy : Hey that's a neat trick
    Noldorin : Fair enough. I suppose one advantage of this method is that you can include an argument with the method specifying some state variable, and then change what string representation is returned depending on this.
    borisCallens : Yes, it all depends on the scope of the method I guess. While the Attribute way is more generic, your solution is more localized.. It's all about needs in the end.
    Will : You can put extension methods anywhere you want. You just have to reference it where you want to use them.
    borisCallens : Yes, but this would mean that this one extention method should be rewritten every time you introduce a new enum you want to have a friendly name for. This would also mean that ALL your applications would carry around friendly names for ALL your other applications...
  • Maybe I'm missing something, but what's wrong with Enum.GetName?

    public string GetName(PublishStatusses value)
    {
      return Enum.GetName(typeof(PublishStatusses), value)
    }
    

    edit: for user-friendly strings, you need to go through a .resource to get internationalisation/localisation done, and it would arguably be better to use a fixed key based on the enum key than a decorator attribute on the same.

    borisCallens : I returns the literal value of the enum, not some user friendly one.
    annakata : oic - well there's a pretty big case that you have to go through a string resource library based on this value then, because the alternative (decorator attribs) won't support I18N
    borisCallens : In case of I18N I would make the GetDescription() method search in the resource lib for a translated string and fall back to the description and then fall back to the literal.
  • I do this with extension methods:

    public enum ErrorLevel
    {
      None,
      Low,
      High,
      SoylentGreen
    }
    
    public static class ErrorLevelExtensions
    {
      public static string ToFriendlyString(this ErrorLevel me)
      {
        switch(me)
        {
          case ErrorLevel.None:
            return "Everything is OK";
          case ErrorLevel.Low:
            return "SNAFU, if you know what I mean.";
          case ErrorLevel.High:
            return "Reaching TARFU levels";
          case ErrorLevel.SoylentGreen:
            return "ITS PEOPLE!!!!";
        }
      }
    }
    
    Will : dangit, noldorim snuck in on me. Giving him an upvote.
    borisCallens : yes, thanks for the input though. I put some remarks in noldorim's post regarding this solution.
    Noldorin : Why, thank you Will.
    Andrew Backer : This is quite nice, actually. Very helpful.
    JustLooking : I love this so much I want to marry it.
  • With respect to Ray Booysen, there is a bug in the code: http://stackoverflow.com/questions/479410/enum-tostring/479417#479417

    You need to account for multiple attributes on the enum values.

    public static string GetDescription<T>(this object enumerationValue)
                where T : struct
        {
            Type type = enumerationValue.GetType();
            if (!type.IsEnum)
            {
                throw new ArgumentException("EnumerationValue must be of Enum type", "enumerationValue");
            }
    
            //Tries to find a DescriptionAttribute for a potential friendly name
            //for the enum
            MemberInfo[] memberInfo = type.GetMember(enumerationValue.ToString());
            if (memberInfo != null && memberInfo.Length > 0)
            {
                object[] attrs = memberInfo[0].GetCustomAttributes(typeof(DescriptionAttribute), false);
    
                if (attrs != null && attrs.Length > 0 && attrs.Where(t => t.GetType() == typeof(DescriptionAttribute)).FirstOrDefault() != null)
                {
                    //Pull out the description value
                    return ((DescriptionAttribute)attrs.Where(t=>t.GetType() == typeof(DescriptionAttribute)).FirstOrDefault()).Description;
                }
            }
            //If we have no description attribute, just return the ToString of the enum
            return enumerationValue.ToString();
    

0 comments:

Post a Comment