960

I have the following enumeration:

public enum AuthenticationMethod
{
    FORMS = 1,
    WINDOWSAUTHENTICATION = 2,
    SINGLESIGNON = 3
}

The problem however is that I need the word "FORMS" when I ask for AuthenticationMethod.FORMS and not the id 1.

I have found the following solution for this problem (link):

First I need to create a custom attribute called "StringValue":

public class StringValue : System.Attribute
{
    private readonly string _value;

    public StringValue(string value)
    {
        _value = value;
    }

    public string Value
    {
        get { return _value; }
    }

}

Then I can add this attribute to my enumeration:

public enum AuthenticationMethod
{
    [StringValue("FORMS")]
    FORMS = 1,
    [StringValue("WINDOWS")]
    WINDOWSAUTHENTICATION = 2,
    [StringValue("SSO")]
    SINGLESIGNON = 3
}

And of course I need something to retrieve that StringValue:

public static class StringEnum
{
    public static string GetStringValue(Enum value)
    {
        string output = null;
        Type type = value.GetType();

        //Check first in our cached results...

        //Look for our 'StringValueAttribute' 

        //in the field's custom attributes

        FieldInfo fi = type.GetField(value.ToString());
        StringValue[] attrs =
           fi.GetCustomAttributes(typeof(StringValue),
                                   false) as StringValue[];
        if (attrs.Length > 0)
        {
            output = attrs[0].Value;
        }

        return output;
    }
}

Good now I've got the tools to get a string value for an enumeration. I can then use it like this:

string valueOfAuthenticationMethod = StringEnum.GetStringValue(AuthenticationMethod.FORMS);

Okay now all of these work like a charm but I find it a whole lot of work. I was wondering if there is a better solution for this.

I also tried something with a dictionary and static properties but that wasn't better either.

7
  • 6
    While you may find this long winded, it's actually a pretty flexible way to go for other things. As one of my colleagues pointed out, this could be used in many cases to replace Enum Helpers that map database codes to enum values etc... Commented Jan 8, 2009 at 16:15
  • 3
    It is an "Enumeration", not an "Enumerator". Commented Jan 9, 2009 at 2:27
  • 29
    MSDN reccoments suffix attribute classes with "Attribute" suffix. So "class StringValueAttribute" ;)
    – serhio
    Commented Jun 30, 2011 at 14:53
  • 14
    I agree with @BenAlabaster this is actually quite flexible. Also, you could make this an extension method just by adding this in front of the Enum in your static method. Then you can do AuthenticationMethod.Forms.GetStringValue(); Commented May 10, 2012 at 18:56
  • 5
    This approach uses reflection to read the attribute values and it is very slow if you have to call GetStringValue() many times in my experience. The type-safe-enum pattern is faster.
    – Rn222
    Commented Mar 3, 2014 at 22:04

37 Answers 37

891

Try type-safe-enum pattern.

public sealed class AuthenticationMethod {

    private readonly String name;
    private readonly int value;

    public static readonly AuthenticationMethod FORMS = new AuthenticationMethod (1, "FORMS");
    public static readonly AuthenticationMethod WINDOWSAUTHENTICATION = new AuthenticationMethod (2, "WINDOWS");
    public static readonly AuthenticationMethod SINGLESIGNON = new AuthenticationMethod (3, "SSN");        

    private AuthenticationMethod(int value, String name){
        this.name = name;
        this.value = value;
    }

    public override String ToString(){
        return name;
    }

}

Update Explicit (or implicit) type conversion can be done by

  • adding static field with mapping

    private static readonly Dictionary<string, AuthenticationMethod> instance = new Dictionary<string,AuthenticationMethod>();
    
    • n.b. In order that the initialisation of the the "enum member" fields doesn't throw a NullReferenceException when calling the instance constructor, be sure to put the Dictionary field before the "enum member" fields in your class. This is because static field initialisers are called in declaration order, and before the static constructor, creating the weird and necessary but confusing situation that the instance constructor can be called before all static fields have been initialised, and before the static constructor is called.
  • filling this mapping in instance constructor

    instance[name] = this;
    
  • and adding user-defined type conversion operator

    public static explicit operator AuthenticationMethod(string str)
    {
        AuthenticationMethod result;
        if (instance.TryGetValue(str, out result))
            return result;
        else
            throw new InvalidCastException();
    }
    
26
  • 23
    It looks like an enum but it isn't an enum. I can imagine that causing some interesting problems if people start trying to compare AuthenticationMethods. You probably need to overload various equality operators too.
    – Ant
    Commented Feb 25, 2010 at 9:18
  • 38
    @Ant: I don't have to. Since we have only one instance of each AuthenticationMethod the reference equality inherited from Object works fine. Commented Feb 26, 2010 at 9:24
  • 10
    @tyriker: Compiler does. The constructor is private so you cannot create new instance. Also static members are not accessible through instance. Commented Oct 14, 2010 at 6:56
  • 21
    @Jakub Very interesting. I had to play with it to figure out how to use it, and realize its benefits. It's a public, non-static class, but can't be instantiated and you can only access its static members. Basically, it behaves like an enum. But the best part...the static members are typed of the class and not a generic string or int. It's a ... [wait for it] ... type safe enum! Thanks for helping me understand.
    – tyriker
    Commented Oct 14, 2010 at 17:56
  • 5
    Love this solution - the only major downside I've hit with it is that it doesn't work in a switch statement - that is, I can use a normal enum or a list of const's in a switch, but not these. Commented Feb 15, 2012 at 21:09
236

Use method

Enum.GetName(Type MyEnumType,  object enumvariable)  

as in (Assume Shipper is a defined Enum)

Shipper x = Shipper.FederalExpress;
string s = Enum.GetName(typeof(Shipper), x);

There are a bunch of other static methods on the Enum class worth investigating too...

12
  • 6
    Exactly. I did make a custom attribute for a string description, but that's because I want a user-friendly version (with spaces and other special characters) that can be easily bound to a ComboBox or such.
    – lc.
    Commented Jan 8, 2009 at 14:21
  • 5
    Enum.GetName reflects the field names in the enum - same as the .ToString(). If performance is an issue it can be a problem. I wouldn't worry about it unless you're converting loads of enums though.
    – Keith
    Commented Jan 8, 2009 at 14:26
  • 8
    Another option to consider, if you need an enum with extra functiuonality, is to "roll yr own" using a struct... you add static readonly named properties to represent the enum values that are initialized to constructors that generate individual instances of the struct... Commented Jan 8, 2009 at 14:39
  • 1
    then you can add whatever other struct members you wish, to implement whatever functionality you want this "enum" to have ... Commented Jan 8, 2009 at 14:40
  • 2
    The issue here is that GetName is not localizable. That isn't always a concern, but it is something to be aware of. Commented Jan 8, 2009 at 14:49
81

You can reference the name rather than the value by using ToString()

Console.WriteLine("Auth method: {0}", AuthenticationMethod.Forms.ToString());

The documentation is here:

http://msdn.microsoft.com/en-us/library/16c1xs4z.aspx

...and if you name your enums in Pascal Case (as I do - such as ThisIsMyEnumValue = 1 etc.) then you could use a very simple regex to print the friendly form:

static string ToFriendlyCase(this string EnumString)
{
    return Regex.Replace(EnumString, "(?!^)([A-Z])", " $1");
}

which can easily be called from any string:

Console.WriteLine("ConvertMyCrazyPascalCaseSentenceToFriendlyCase".ToFriendlyCase());

Outputs:

Convert My Crazy Pascal Case Sentence To Friendly Case

That saves running all the way around the houses creating custom attributes and attaching them to your enums or using lookup tables to marry an enum value with a friendly string and best of all it's self managing and can be used on any Pascal Case string which is infinitely more reusable. Of course, it doesn't allow you to have a different friendly name than your enum which your solution does provide.

I do like your original solution though for more complex scenarios though. You could take your solution one step further and make your GetStringValue an extension method of your enum and then you wouldn't need to reference it like StringEnum.GetStringValue...

public static string GetStringValue(this AuthenticationMethod value)
{
  string output = null;
  Type type = value.GetType();
  FieldInfo fi = type.GetField(value.ToString());
  StringValue[] attrs = fi.GetCustomAttributes(typeof(StringValue), false) as StringValue[];
  if (attrs.Length > 0)
    output = attrs[0].Value;
  return output;
}

You could then access it easily straight from your enum instance:

Console.WriteLine(AuthenticationMethod.SSO.GetStringValue());
5
  • 2
    This doesn't help if the "friendly name" needs a space. Such as "Forms Authentication" Commented Jan 8, 2009 at 14:26
  • 4
    So make sure the enum is named with caps like FormsAuthentication and insert a space before any caps that aren't at the beginning. It's not rocket science to insert a space in a string... Commented Jan 8, 2009 at 15:10
  • 4
    The auto-spacing of Pascal Case names becomes problematic if they contain abbreviations that should be capitalised, XML or GPS for example.
    – Richard Ev
    Commented Jul 20, 2012 at 13:47
  • 3
    @RichardEv, there's no perfect regex for this but here is one that should work a little better with abbreviations. "(?!^)([^A-Z])([A-Z])", "$1 $2". So HereIsATEST becomes Here Is ATEST.
    – sparebytes
    Commented Aug 12, 2013 at 23:51
  • Not elegent doing these little "hacks" which is what they are. I get what the OP is saying and I am trying to find a similar solution i.e. using the elegance of Enums but being able to readily access the associated message. Only solution I can think of is to apply some kind of mapping between the enum name and a string value but that doesn't get arround the issue of maintaining the string data (however makes it practical for scenarios where you need to have multi regions etc)
    – Trevor
    Commented Apr 1, 2017 at 19:35
76

Unfortunately reflection to get attributes on enums is quite slow:

See this question: Anyone know a quick way to get to custom attributes on an enum value?

The .ToString() is quite slow on enums too.

You can write extension methods for enums though:

public static string GetName( this MyEnum input ) {
    switch ( input ) {
        case MyEnum.WINDOWSAUTHENTICATION:
            return "Windows";
        //and so on
    }
}

This isn't great, but will be quick and not require the reflection for attributes or field name.


C#6 Update

If you can use C#6 then the new nameof operator works for enums, so nameof(MyEnum.WINDOWSAUTHENTICATION) will be converted to "WINDOWSAUTHENTICATION" at compile time, making it the quickest way to get enum names.

Note that this will convert the explicit enum to an inlined constant, so it doesn't work for enums that you have in a variable. So:

nameof(AuthenticationMethod.FORMS) == "FORMS"

But...

var myMethod = AuthenticationMethod.FORMS;
nameof(myMethod) == "myMethod"
10
  • 24
    You can fetch the attribute values once and put them in a Dictionary<MyEnum,string> to keep the declarative aspect.
    – Jon Skeet
    Commented Jan 8, 2009 at 14:38
  • 1
    Yeah that's what we ended up doing in an app with lots of enums when we found out that the reflection was the bottle-neck.
    – Keith
    Commented Jan 8, 2009 at 16:04
  • Thanks Jon and Keith, I ended up using your Dictionary suggestion. Works great (and fast!). Commented Nov 23, 2010 at 22:22
  • @JonSkeet I know this is old. But how would one achieve this?
    – tinonetic
    Commented Feb 12, 2015 at 13:22
  • 2
    @user919426: Achieve want? Putting them in a dictionary? Just create a dictionary, ideally with a collection initializer... it's not clear what you're asking for.
    – Jon Skeet
    Commented Feb 12, 2015 at 13:52
61

I use an extension method:

public static class AttributesHelperExtension
    {
        public static string ToDescription(this Enum value)
        {
            var da = (DescriptionAttribute[])(value.GetType().GetField(value.ToString())).GetCustomAttributes(typeof(DescriptionAttribute), false);
            return da.Length > 0 ? da[0].Description : value.ToString();
        }
}

Now decorate the enum with:

public enum AuthenticationMethod
{
    [Description("FORMS")]
    FORMS = 1,
    [Description("WINDOWSAUTHENTICATION")]
    WINDOWSAUTHENTICATION = 2,
    [Description("SINGLESIGNON ")]
    SINGLESIGNON = 3
}

When you call

AuthenticationMethod.FORMS.ToDescription() you will get "FORMS".

3
  • 1
    I had to add using System.ComponentModel; Also, this method only works if you want the String value to be the same as the Enum's name. OP wanted a different value.
    – elcool
    Commented Jan 23, 2013 at 15:02
  • 3
    Don't you mean when you call AuthenticationMethod.FORMS.ToDescription()? Commented Feb 1, 2014 at 19:56
  • This solution works great and does allow the description to be different from the Enum variable name. Commented Jul 7, 2022 at 13:21
42

Just use the ToString() method

public enum any{Tomato=0,Melon,Watermelon}

To reference the string Tomato, just use

any.Tomato.ToString();
5
  • Wow. That was easy. I know the OP wanted to add custom string descriptions, but this is what I needed. I should have known to try this, in retrospect, but I went down the Enum.GetName route.
    – Rafe
    Commented Sep 23, 2012 at 6:52
  • 18
    @Brent Because most often you have the .ToString() value different than the user-friendly value you need.
    – Novitchi S
    Commented Apr 23, 2014 at 13:35
  • 2
    @Brent - because this is different than the question being asked. The question being ask is how to you get this string from a variable that has been assigned an enumerated value. That is dynamic at run time. This is checking the definition of the type and set at run time.
    – Hogan
    Commented Jul 10, 2015 at 19:03
  • 1
    @Hogan - the ToString() works on variables as well: any fruit = any.Tomato; string tomato = fruit.ToString();
    – LiborV
    Commented Jul 14, 2017 at 14:49
  • @LiborV - please remember this was written in 09 -- C# was different then and ToString() on an instance of an enumeration did something different.
    – Hogan
    Commented Jul 14, 2017 at 20:16
31

Very simple solution to this with .Net 4.0 and above. No other code is needed.

public enum MyStatus
{
    Active = 1,
    Archived = 2
}

To get the string about just use:

MyStatus.Active.ToString("f");

or

MyStatus.Archived.ToString("f");`

The value will be "Active" or "Archived".

To see the different string formats (the "f" from above) when calling Enum.ToString see this Enumeration Format Strings page

0
28

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();

        }

As an example:

public enum Cycle : int
{        
   [Description("Daily Cycle")]
   Daily = 1,
   Weekly,
   Monthly
}

This code nicely caters for enums where you don't need a "Friendly name" and will return just the .ToString() of the enum.

0
28

I really like Jakub Šturc's answer, but it's shortcoming is that you cannot use it with a switch-case statement. Here's a slightly modified version of his answer that can be used with a switch statement:

public sealed class AuthenticationMethod
{
    #region This code never needs to change.
    private readonly string _name;
    public readonly Values Value;

    private AuthenticationMethod(Values value, String name){
        this._name = name;
        this.Value = value;
    }

    public override String ToString(){
        return _name;
    }
    #endregion

    public enum Values
    {
        Forms = 1,
        Windows = 2,
        SSN = 3
    }

    public static readonly AuthenticationMethod FORMS = new AuthenticationMethod (Values.Forms, "FORMS");
    public static readonly AuthenticationMethod WINDOWSAUTHENTICATION = new AuthenticationMethod (Values.Windows, "WINDOWS");
    public static readonly AuthenticationMethod SINGLESIGNON = new AuthenticationMethod (Values.SSN, "SSN");
}

So you get all of the benefits of Jakub Šturc's answer, plus we can use it with a switch statement like so:

var authenticationMethodVariable = AuthenticationMethod.FORMS;  // Set the "enum" value we want to use.
var methodName = authenticationMethodVariable.ToString();       // Get the user-friendly "name" of the "enum" value.

// Perform logic based on which "enum" value was chosen.
switch (authenticationMethodVariable.Value)
{
    case authenticationMethodVariable.Values.Forms: // Do something
        break;
    case authenticationMethodVariable.Values.Windows: // Do something
        break;
    case authenticationMethodVariable.Values.SSN: // Do something
        break;      
}
5
  • A shorter solution would be to remove the enums {} and instead keep a static count of how many Enums you have constructed. This also gives the benefit that you don't have to add a new instance you make to the enum list. e.g. public static int nextAvailable { get; private set; } then in the constructor this.Value = nextAvailable++;
    – Slate
    Commented Feb 5, 2014 at 21:42
  • Interesting idea @kjhf. My concern though would be that if somebody reorders the code, then the value assigned to the enum values might change as well. For example, this could result in the wrong enum value being retrieved when the enum value is saved to a file/database, the order of the "new AuthenticationMethod(...)" lines are changed (e.g. one is removed), and then running the app again and retrieving the enum value from the file/database; the enum value may not match the AuthenticationMethod that was originally saved.
    – deadlydog
    Commented Feb 5, 2014 at 21:50
  • Good point - though I hope in these particular cases people won't be relying on the enum's integer value (or reordering enum code.) -- and this value is purely used as a switch and possibly an alternative to .Equals() and .GetHashCode(). If concerned, you could always put a huge comment with "DO NOT REORDER" :p
    – Slate
    Commented Feb 5, 2014 at 22:30
  • Can't you just overload the = operator to allow switch to work? I did this in VB and can now use it in select case statement. Commented Aug 19, 2014 at 10:38
  • @user1318499 No, C# has stricter rules around the switch statement than VB. You can't use class instances for the Case statement; you can only use constant primitives.
    – deadlydog
    Commented Aug 19, 2014 at 22:22
13

I use a combination of several of the suggestions above, combined with some caching. Now, I got the idea from some code that I found somewhere on the net, but I can neither remember where I got it or find it. So if anyone ever finds something that looks similar please comment with the attribution.

Anyway, the usage involves the type converters, so if you are binding to the UI it 'just works'. You can extended with Jakub's pattern for quick code lookup by initializing from the type converter into the static methods.

The base usage would look like this

[TypeConverter(typeof(CustomEnumTypeConverter<MyEnum>))]
public enum MyEnum
{
    // The custom type converter will use the description attribute
    [Description("A custom description")]
    ValueWithCustomDescription,

   // This will be exposed exactly.
   Exact
}

The code for the custom enum type converter follows:

public class CustomEnumTypeConverter<T> : EnumConverter
    where T : struct
{
    private static readonly Dictionary<T,string> s_toString = 
      new Dictionary<T, string>();

    private static readonly Dictionary<string, T> s_toValue = 
      new Dictionary<string, T>();

    private static bool s_isInitialized;

    static CustomEnumTypeConverter()
    {
        System.Diagnostics.Debug.Assert(typeof(T).IsEnum,
          "The custom enum class must be used with an enum type.");
    }

    public CustomEnumTypeConverter() : base(typeof(T))
    {
        if (!s_isInitialized)
        {
            Initialize();
            s_isInitialized = true;
        }
    }

    protected void Initialize()
    {
        foreach (T item in Enum.GetValues(typeof(T)))
        {
            string description = GetDescription(item);
            s_toString[item] = description;
            s_toValue[description] = item;
        }
    }

    private static string GetDescription(T optionValue)
    {
        var optionDescription = optionValue.ToString();
        var optionInfo = typeof(T).GetField(optionDescription);
        if (Attribute.IsDefined(optionInfo, typeof(DescriptionAttribute)))
        {
            var attribute = 
              (DescriptionAttribute)Attribute.
                 GetCustomAttribute(optionInfo, typeof(DescriptionAttribute));
            return attribute.Description;
        }
        return optionDescription;
    }

    public override object ConvertTo(ITypeDescriptorContext context, 
       System.Globalization.CultureInfo culture, 
       object value, Type destinationType)
    {
        var optionValue = (T)value;

        if (destinationType == typeof(string) && 
            s_toString.ContainsKey(optionValue))
        {
            return s_toString[optionValue];
        }

        return base.ConvertTo(context, culture, value, destinationType);
    }

    public override object ConvertFrom(ITypeDescriptorContext context, 
       System.Globalization.CultureInfo culture, object value)
    {
        var stringValue = value as string;

        if (!string.IsNullOrEmpty(stringValue) && s_toValue.ContainsKey(stringValue))
        {
            return s_toValue[stringValue];
        }

        return base.ConvertFrom(context, culture, value);
    }
}

}

2
  • How to use it? thank. ex: MyEnum.ValueWithCustomDescription.??() or something? Commented Aug 31, 2020 at 7:02
  • This answer was written about a decade ago, so I'm really not sure about the original context. The problem with SO is that it is around forever. I believe this was in relation to adding data to be shown on UIs like WinForms or WPF, in which case just binding the property or collection to the UI control would pick up the type converter directly. Commented Sep 1, 2020 at 16:02
12

In your question you never said that you actually need the numeric value of the enum anywhere.

If you do not and just need an enum of type string (which is not an integral type so can not be a base of enum) here is a way:

    static class AuthenticationMethod
    {
        public static readonly string
            FORMS = "Forms",
            WINDOWSAUTHENTICATION = "WindowsAuthentication";
    }

you can use the same syntax as enum to reference it

if (bla == AuthenticationMethod.FORMS)

It will be a bit slower than with numeric values (comparing strings instead of numbers) but on the plus side it is not using reflection (slow) to access the string.

1
  • if you use "const" instead of "static readonly" then you can use the values as case labels in a switch statement.
    – Eben Stone
    Commented Aug 1, 2017 at 14:33
12

Update: Visiting this page, 8 years later, after not touching C# for a long while, looks like my answer is no longer the best solution. I really like the converter solution tied with attribute-functions.

If you are reading this, please make sure you also check out other answers.
(hint: they are above this one)


As most of you, I really liked the selected answer by Jakub Šturc, but I also really hate to copy-paste code, and try to do it as little as I can.

So I decided I wanted an EnumBase class from which most of the functionality is inherited/built-in, leaving me to focus on the content instead of behavior.

The main problem with this approach is based on the fact that although Enum values are type-safe instances, the interaction is with the Static implementation of the Enum Class type. So with a little help of generics magic, I think I finally got the correct mix. Hope someone finds this as useful as I did.

I'll start with Jakub's example, but using inheritance and generics:

public sealed class AuthenticationMethod : EnumBase<AuthenticationMethod, int>
{
    public static readonly AuthenticationMethod FORMS =
        new AuthenticationMethod(1, "FORMS");
    public static readonly AuthenticationMethod WINDOWSAUTHENTICATION =
        new AuthenticationMethod(2, "WINDOWS");
    public static readonly AuthenticationMethod SINGLESIGNON =
        new AuthenticationMethod(3, "SSN");

    private AuthenticationMethod(int Value, String Name)
        : base( Value, Name ) { }
    public new static IEnumerable<AuthenticationMethod> All
    { get { return EnumBase<AuthenticationMethod, int>.All; } }
    public static explicit operator AuthenticationMethod(string str)
    { return Parse(str); }
}

And here is the base class:

using System;
using System.Collections.Generic;
using System.Linq; // for the .AsEnumerable() method call

// E is the derived type-safe-enum class
// - this allows all static members to be truly unique to the specific
//   derived class
public class EnumBase<E, T> where E: EnumBase<E, T>
{
    #region Instance code
    public T Value { get; private set; }
    public string Name { get; private set; }

    protected EnumBase(T EnumValue, string Name)
    {
        Value = EnumValue;
        this.Name = Name;
        mapping.Add(Name, this);
    }

    public override string ToString() { return Name; }
    #endregion

    #region Static tools
    static private readonly Dictionary<string, EnumBase<E, T>> mapping;
    static EnumBase() { mapping = new Dictionary<string, EnumBase<E, T>>(); }
    protected static E Parse(string name)
    {
        EnumBase<E, T> result;
        if (mapping.TryGetValue(name, out result))
        {
            return (E)result;
        }

        throw new InvalidCastException();
    }
    // This is protected to force the child class to expose it's own static
    // method.
    // By recreating this static method at the derived class, static
    // initialization will be explicit, promising the mapping dictionary
    // will never be empty when this method is called.
    protected static IEnumerable<E> All
    { get { return mapping.Values.AsEnumerable().Cast<E>(); } }
    #endregion
}
1
  • You may be able to call the derived static constructor from the base static constructor. I'm still looking into it, but so far I have found no issues with it: stackoverflow.com/questions/55290034/…
    – Cory-G
    Commented Mar 21, 2019 at 23:34
11

How I solved this as an extension method:

using System.ComponentModel;
public static string GetDescription(this Enum value)
{
    var descriptionAttribute = (DescriptionAttribute)value.GetType()
        .GetField(value.ToString())
        .GetCustomAttributes(false)
        .Where(a => a is DescriptionAttribute)
        .FirstOrDefault();

    return descriptionAttribute != null ? descriptionAttribute.Description : value.ToString();
}

Enum:

public enum OrderType
{
    None = 0,
    [Description("New Card")]
    NewCard = 1,
    [Description("Reload")]
    Refill = 2
}

Usage (where o.OrderType is a property with the same name as the enum):

o.OrderType.GetDescription()

Which gives me a string of "New Card" or "Reload" instead of the actual enum value NewCard and Refill.

2
  • For completeness you should include a copy of your DescriptionAttribute class. Commented Apr 21, 2012 at 10:03
  • 3
    Bernie, DescriptionAttribute is in System.ComponentModel
    – agentnega
    Commented May 8, 2012 at 16:00
11

If you've come here looking to implement a simple "Enum" but whose values are strings instead of ints, here is the simplest solution:

    public sealed class MetricValueList
    {
        public static readonly string Brand = "A4082457-D467-E111-98DC-0026B9010912";
        public static readonly string Name = "B5B5E167-D467-E111-98DC-0026B9010912";
    }

Implementation:

var someStringVariable = MetricValueList.Brand;
2
  • 2
    It's probably better to make the variables consts instead of using static readonly.
    – AndrewL
    Commented Apr 22, 2013 at 17:35
  • 3
    consts are not good for publicly accessible classes, as they are baked in compile time, you cannot replace a third party DLL without recompiling your whole code with consts.The performance offset of consts vs static readonly is negligible. Commented Aug 24, 2017 at 10:46
10

I agree with Keith, but I can't vote up (yet).

I use a static method and swith statement to return exactly what I want. In the database I store tinyint and my code only uses the actual enum, so the strings are for UI requirements. After numerous testing this resulted in the best performance and most control over the output.

public static string ToSimpleString(this enum)
{
     switch (enum)
     {
         case ComplexForms:
             return "ComplexForms";
             break;
     }
}

public static string ToFormattedString(this enum)
{
     switch (enum)
     {
         case ComplexForms:
             return "Complex Forms";
             break;
     }
}

However, by some accounts, this leads to a possible maintenance nightmare and some code smell. I try to keep an eye for enums that are long and a lot of enums, or those that change frequently. Otherwise, this has been a great solution for me.

0
7

When I'm confronted with this problem, there are a couple of questions that I try to find the answers to first:

  • Are the names of my enum values sufficiently friendly for the purpose, or do I need to provide friendlier ones?
  • Do I need to round-trip? That is, will I need to take text values and parse them into enum values?
  • Is this something I need to do for many enums in my project, or just one?
  • What kind of UI elements will I be presenting this information in - in particular, will I be binding to the UI, or using property sheets?
  • Does this need to be localizable?

The simplest way to do this is with Enum.GetValue (and support round-tripping using Enum.Parse). It's also often worth building a TypeConverter, as Steve Mitcham suggests, to support UI binding. (It's not necessary to build a TypeConverter when you're using property sheets, which is one of the nice things about property sheets. Though lord knows they have their own issues.)

In general, if the answers to the above questions suggest that's not going to work, my next step is to create and populate a static Dictionary<MyEnum, string>, or possibly a Dictionary<Type, Dictionary<int, string>>. I tend to skip the intermediate decorate-the-code-with-attributes step because what's usually coming down the pike next is the need to change the friendly values after deployment (often, but not always, because of localization).

7

I created a base class for creating string-valued enums in .NET. It is just one C# file that you can copy & paste into your projects, or install via NuGet package named StringEnum. GitHub Repo

  • Intellisense will suggest the enum name if the class is annotated with the xml comment <completitionlist>. (Works in both C# and VB)

Intellisense demo

  • Usage similar to a regular enum:
///<completionlist cref="HexColor"/> 
class HexColor : StringEnum<HexColor>
{
    public static readonly HexColor Blue = Create("#FF0000");
    public static readonly HexColor Green = Create("#00FF00");
    public static readonly HexColor Red = Create("#000FF");
}
    // Static Parse Method
    HexColor.Parse("#FF0000") // => HexColor.Red
    HexColor.Parse("#ff0000", caseSensitive: false) // => HexColor.Red
    HexColor.Parse("invalid") // => throws InvalidOperationException

    // Static TryParse method.
    HexColor.TryParse("#FF0000") // => HexColor.Red
    HexColor.TryParse("#ff0000", caseSensitive: false) // => HexColor.Red
    HexColor.TryParse("invalid") // => null

    // Parse and TryParse returns the preexistent instances
    object.ReferenceEquals(HexColor.Parse("#FF0000"), HexColor.Red) // => true

    // Conversion from your `StringEnum` to `string`
    string myString1 = HexColor.Red.ToString(); // => "#FF0000"
    string myString2 = HexColor.Red; // => "#FF0000" (implicit cast)

Instalation:

  • Paste the following StringEnum base class to your project. (latest version)
  • Or install StringEnum NuGet package, which is based on .Net Standard 1.0 so it runs on .Net Core >= 1.0, .Net Framework >= 4.5, Mono >= 4.6, etc.
    /// <summary>
    /// Base class for creating string-valued enums in .NET.<br/>
    /// Provides static Parse() and TryParse() methods and implicit cast to string.
    /// </summary>
    /// <example> 
    /// <code>
    /// class Color : StringEnum &lt;Color&gt;
    /// {
    ///     public static readonly Color Blue = Create("Blue");
    ///     public static readonly Color Red = Create("Red");
    ///     public static readonly Color Green = Create("Green");
    /// }
    /// </code>
    /// </example>
    /// <typeparam name="T">The string-valued enum type. (i.e. class Color : StringEnum&lt;Color&gt;)</typeparam>
    public abstract class StringEnum<T> : IEquatable<T> where T : StringEnum<T>, new()
    {
        protected string Value;
        private static Dictionary<string, T> valueDict = new Dictionary<string, T>();
        protected static T Create(string value)
        {
            if (value == null)
                return null; // the null-valued instance is null.

            var result = new T() { Value = value };
            valueDict.Add(value, result);
            return result;
        }

        public static implicit operator string(StringEnum<T> enumValue) => enumValue.Value;
        public override string ToString() => Value;

        public static bool operator !=(StringEnum<T> o1, StringEnum<T> o2) => o1?.Value != o2?.Value;
        public static bool operator ==(StringEnum<T> o1, StringEnum<T> o2) => o1?.Value == o2?.Value;

        public override bool Equals(object other) => this.Value.Equals((other as T)?.Value ?? (other as string));
        bool IEquatable<T>.Equals(T other) => this.Value.Equals(other.Value);
        public override int GetHashCode() => Value.GetHashCode();

        /// <summary>
        /// Parse the <paramref name="value"/> specified and returns a valid <typeparamref name="T"/> or else throws InvalidOperationException.
        /// </summary>
        /// <param name="value">The string value representad by an instance of <typeparamref name="T"/>. Matches by string value, not by the member name.</param>
        /// <param name="caseSensitive">If true, the strings must match case and takes O(log n). False allows different case but is little bit slower (O(n))</param>
        public static T Parse(string value, bool caseSensitive = true)
        {
            var result = TryParse(value, caseSensitive);
            if (result == null)
                throw new InvalidOperationException((value == null ? "null" : $"'{value}'") + $" is not a valid {typeof(T).Name}");

            return result;
        }

        /// <summary>
        /// Parse the <paramref name="value"/> specified and returns a valid <typeparamref name="T"/> or else returns null.
        /// </summary>
        /// <param name="value">The string value representad by an instance of <typeparamref name="T"/>. Matches by string value, not by the member name.</param>
        /// <param name="caseSensitive">If true, the strings must match case. False allows different case but is slower: O(n)</param>
        public static T TryParse(string value, bool caseSensitive = true)
        {
            if (value == null) return null;
            if (valueDict.Count == 0) System.Runtime.CompilerServices.RuntimeHelpers.RunClassConstructor(typeof(T).TypeHandle); // force static fields initialization
            if (caseSensitive)
            {
                if (valueDict.TryGetValue(value, out T item))
                    return item;
                else
                    return null;
            }
            else
            {
                // slower O(n) case insensitive search
                return valueDict.FirstOrDefault(f => f.Key.Equals(value, StringComparison.OrdinalIgnoreCase)).Value;
                // Why Ordinal? => https://esmithy.net/2007/10/15/why-stringcomparisonordinal-is-usually-the-right-choice/
            }
        }
    }
6

I wanted to post this as a comment to the post quoted below but couldn't because I don't have enough rep. The code contained an error and I wanted to point this out to individuals trying to use this solution:

[TypeConverter(typeof(CustomEnumTypeConverter(typeof(MyEnum))]
public enum MyEnum
{
  // The custom type converter will use the description attribute
  [Description("A custom description")]
  ValueWithCustomDescription,
  // This will be exposed exactly.
  Exact
}

should be

[TypeConverter(typeof(CustomEnumTypeConverter<MyEnum>))]
public enum MyEnum
{
  // The custom type converter will use the description attribute
  [Description("A custom description")]
  ValueWithCustomDescription,

  // This will be exposed exactly.
  Exact
}
5

My variant

public struct Colors
{
    private String current;

    private static string red = "#ff0000";
    private static string green = "#00ff00";
    private static string blue = "#0000ff";

    private static IList<String> possibleColors; 

    public static Colors Red { get { return (Colors) red; } }
    public static Colors Green { get { return (Colors) green; } }
    public static Colors Blue { get { return (Colors) blue; } }

    static Colors()
    {
        possibleColors = new List<string>() {red, green, blue};
    }

    public static explicit operator String(Colors value)
    {
        return value.current;
    }

    public static explicit operator Colors(String value)
    {
        if (!possibleColors.Contains(value))
        {
            throw new InvalidCastException();
        }

        Colors color = new Colors();
        color.current = value;
        return color;
    }

    public static bool operator ==(Colors left, Colors right)
    {
        return left.current == right.current;
    }

    public static bool operator !=(Colors left, Colors right)
    {
        return left.current != right.current;
    }

    public bool Equals(Colors other)
    {
        return Equals(other.current, current);
    }

    public override bool Equals(object obj)
    {
        if (ReferenceEquals(null, obj)) return false;
        if (obj.GetType() != typeof(Colors)) return false;
        return Equals((Colors)obj);
    }

    public override int GetHashCode()
    {
        return (current != null ? current.GetHashCode() : 0);
    }

    public override string ToString()
    {
        return current;
    }
}

Code looks a bit ugly, but usages of this struct are pretty presentative.

Colors color1 = Colors.Red;
Console.WriteLine(color1); // #ff0000

Colors color2 = (Colors) "#00ff00";
Console.WriteLine(color2); // #00ff00

// Colors color3 = "#0000ff"; // Compilation error
// String color4 = Colors.Red; // Compilation error

Colors color5 = (Colors)"#ff0000";
Console.WriteLine(color1 == color5); // True

Colors color6 = (Colors)"#00ff00";
Console.WriteLine(color1 == color6); // False

Also, I think, if a lot of such enums required, code generation (e.g. T4) might be used.

4

Option 1:

public sealed class FormsAuth
{
     public override string ToString{return "Forms Authtentication";}
}
public sealed class WindowsAuth
{
     public override string ToString{return "Windows Authtentication";}
}

public sealed class SsoAuth
{
     public override string ToString{return "SSO";}
}

and then

object auth = new SsoAuth(); //or whatever

//...
//...
// blablabla

DoSomethingWithTheAuth(auth.ToString());

Option 2:

public enum AuthenticationMethod
{
        FORMS = 1,
        WINDOWSAUTHENTICATION = 2,
        SINGLESIGNON = 3
}

public class MyClass
{
    private Dictionary<AuthenticationMethod, String> map = new Dictionary<AuthenticationMethod, String>();
    public MyClass()
    {
         map.Add(AuthenticationMethod.FORMS,"Forms Authentication");
         map.Add(AuthenticationMethod.WINDOWSAUTHENTICATION ,"Windows Authentication");
         map.Add(AuthenticationMethod.SINGLESIGNON ,"SSo Authentication");
    }
}
4

If you think about the problem we're trying to solve, it's not an enum we need at all. We need an object that allows a certain number of values to be associated with eachother; in other words, to define a class.

Jakub Šturc's type-safe enum pattern is the best option I see here.

Look at it:

  • It has a private constructor so only the class itself can define the allowed values.
  • It is a sealed class so values can't be modifed through inheritence.
  • It is type-safe, allowing your methods to require only that type.
  • There is no reflection performance hit incurred by accessing the values.
  • And lastly, it can be modified to associate more than two fields together, for example a Name, Description, and a numeric Value.
4

for me, the pragmatic approach is class inside class, sample:

public class MSEModel
{
    class WITS
    {
        public const string DATE = "5005";
        public const string TIME = "5006";
        public const string MD = "5008";
        public const string ROP = "5075";
        public const string WOB = "5073";
        public const string RPM = "7001";
... 
    }
3

Here is yet another way to accomplish the task of associating strings with enums:

struct DATABASE {
    public enum enums {NOTCONNECTED, CONNECTED, ERROR}
    static List<string> strings =
        new List<string>() {"Not Connected", "Connected", "Error"};

    public string GetString(DATABASE.enums value) {
        return strings[(int)value];
    }
}

This method is called like this:

public FormMain() {
    DATABASE dbEnum;

    string enumName = dbEnum.GetString(DATABASE.enums.NOTCONNECTED);
}

You can group related enums in their own struct. Since this method uses the enum type, you can use Intellisense to display the list of enums when making the GetString() call.

You can optionally use the new operator on the DATABASE struct. Not using it means the strings List is not allocated until the first GetString() call is made.

3

A lot of great answers here but in my case did not solve what I wanted out of an "string enum", which was:

  1. Usable in a switch statement e.g switch(myEnum)
  2. Can be used in function parameters e.g. foo(myEnum type)
  3. Can be referenced e.g. myEnum.FirstElement
  4. I can use strings e.g. foo("FirstElement") == foo(myEnum.FirstElement)

1,2 & 4 can actually be solved with a C# Typedef of a string (since strings are switchable in c#)

3 can be solved by static const strings. So if you have the same needs, this is the simplest approach:

public sealed class Types
{

    private readonly String name;

    private Types(String name)
    {
        this.name = name;

    }

    public override String ToString()
    {
        return name;
    }

    public static implicit operator Types(string str)
    {
        return new Types(str);

    }
    public static implicit operator string(Types str)
    {
        return str.ToString();
    }


    #region enum

    public const string DataType = "Data";
    public const string ImageType = "Image";
    public const string Folder = "Folder";
    #endregion

}

This allows for example:

    public TypeArgs(Types SelectedType)
    {
        Types SelectedType = SelectedType
    }

and

public TypeObject CreateType(Types type)
    {
        switch (type)
        {

            case Types.ImageType:
              //
                break;

            case Types.DataType:
             //
                break;

        }
    }

Where CreateType can be called with a string or a type. However the downside is that any string is automatically a valid enum, this could be modified but then it would require some kind of init function...or possibly make they explicit cast internal?

Now if an int value was important to you (perhaps for comparison speed), you could use some ideas from Jakub Šturc fantastic answer and do something a bit crazy, this is my stab at it:

    public sealed class Types
{
    private static readonly Dictionary<string, Types> strInstance = new Dictionary<string, Types>();
    private static readonly Dictionary<int, Types> intInstance = new Dictionary<int, Types>();

    private readonly String name;
    private static int layerTypeCount = 0;
    private int value;
    private Types(String name)
    {
        this.name = name;
        value = layerTypeCount++;
        strInstance[name] = this;
        intInstance[value] = this;
    }

    public override String ToString()
    {
        return name;
    }


    public static implicit operator Types(int val)
    {
        Types result;
        if (intInstance.TryGetValue(val, out result))
            return result;
        else
            throw new InvalidCastException();
    }

    public static implicit operator Types(string str)
    {
        Types result;
        if (strInstance.TryGetValue(str, out result))
        {
            return result;
        }
        else
        {
            result = new Types(str);
            return result;
        }

    }
    public static implicit operator string(Types str)
    {
        return str.ToString();
    }

    public static bool operator ==(Types a, Types b)
    {
        return a.value == b.value;
    }
    public static bool operator !=(Types a, Types b)
    {
        return a.value != b.value;
    }

    #region enum

    public const string DataType = "Data";
    public const string ImageType = "Image";

    #endregion

}

but of course "Types bob = 4;" would be meaningless unless you had initialized them first which would sort of defeat the point...

But in theory TypeA == TypeB would be quicker...

0
3

If I'm understanding you correctly, you can simply use .ToString() to retrieve the name of the enum from the value (Assuming it's already cast as the Enum); If you had the naked int (lets say from a database or something) you can first cast it to the enum. Both methods below will get you the enum name.

AuthenticationMethod myCurrentSetting = AuthenticationMethod.FORMS;
Console.WriteLine(myCurrentSetting); // Prints: FORMS
string name = Enum.GetNames(typeof(AuthenticationMethod))[(int)myCurrentSetting-1];
Console.WriteLine(name); // Prints: FORMS

Keep in mind though, the second technique assumes you are using ints and your index is 1 based (not 0 based). The function GetNames also is quite heavy by comparison, you are generating a whole array each time it's called. As you can see in the first technique, .ToString() is actually called implicitly. Both of these are already mentioned in the answers of course, I'm just trying to clarify the differences between them.

3

old post but...

The answer to this may actually be very simple. Use Enum.ToString() function

There are 6 overloads of this function, you can use Enum.Tostring("F") or Enum.ToString() to return the string value. No need to bother with anything else. Here is a working Demo

Note that this solution may not work for all compilers (this demo does not work as expected) but at least it works for the latest compiler.

2

based on the MSDN: http://msdn.microsoft.com/en-us/library/cc138362.aspx

foreach (string str in Enum.GetNames(typeof(enumHeaderField)))
{
    Debug.WriteLine(str);
}

str will be the names of the fields

1
2

Well, after reading all of the above I feel that the guys have over complicated the issue of transforming enumerators into strings. I liked the idea of having attributes over enumerated fields but i think that attributes are mainly used for Meta-data, but in your case i think that all you need is some sort of localization.

public enum Color 
{ Red = 1, Green = 2, Blue = 3}


public static EnumUtils 
{
   public static string GetEnumResourceString(object enumValue)
    {
        Type enumType = enumValue.GetType();
        string value = Enum.GetName(enumValue.GetType(), enumValue);
        string resourceKey = String.Format("{0}_{1}", enumType.Name, value);
        string result = Resources.Enums.ResourceManager.GetString(resourceKey);
        if (string.IsNullOrEmpty(result))
        {
            result = String.Format("{0}", value);
        }
        return result;
    }
}

Now if we try to call the above method we can call it this way

public void Foo()
{
  var col = Color.Red;
  Console.WriteLine (EnumUtils.GetEnumResourceString (col));
}

All you need to do is just create a resource file containing all the enumerator values and the corresponding strings

Resource Name          Resource Value
Color_Red              My String Color in Red
Color_Blue             Blueeey
Color_Green            Hulk Color

What is actually very nice about that is that it will be very helpful if you need your application to be localized, since all you need to do is just create another resource file with your new language! and Voe-la!

2
Enum.GetName(typeof(MyEnum), (int)MyEnum.FORMS)
Enum.GetName(typeof(MyEnum), (int)MyEnum.WINDOWSAUTHENTICATION)
Enum.GetName(typeof(MyEnum), (int)MyEnum.SINGLESIGNON)

outputs are:

"FORMS"

"WINDOWSAUTHENTICATION"

"SINGLESIGNON"

1

When I am in a situation like that I propose the solution below.

And as a consuming class you could have

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

namespace MyApp.Dictionaries
{
    class Greek
    {

        public static readonly string Alpha = "Alpha";
        public static readonly string Beta = "Beta";
        public static readonly string Gamma = "Gamma";
        public static readonly string Delta = "Delta";


        private static readonly BiDictionary<int, string> Dictionary = new BiDictionary<int, string>();


        static Greek() {
            Dictionary.Add(1, Alpha);
            Dictionary.Add(2, Beta);
            Dictionary.Add(3, Gamma);
            Dictionary.Add(4, Delta);
        }

        public static string getById(int id){
            return Dictionary.GetByFirst(id);
        }

        public static int getByValue(string value)
        {
            return Dictionary.GetBySecond(value);
        }

    }
}

And using a bidirectional dictionary: Based on this (https://stackoverflow.com/a/255638/986160) assuming that the keys will be associated with single values in the dictionary and similar to (https://stackoverflow.com/a/255630/986160) but a bit more elegant. This dictionary is also enumerable and you can go back and forth from ints to strings. Also you don't have to have any string in your codebase with the exception of this class.

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

namespace MyApp.Dictionaries
{

    class BiDictionary<TFirst, TSecond> : IEnumerable
    {
        IDictionary<TFirst, TSecond> firstToSecond = new Dictionary<TFirst, TSecond>();
        IDictionary<TSecond, TFirst> secondToFirst = new Dictionary<TSecond, TFirst>();

        public void Add(TFirst first, TSecond second)
        {
            firstToSecond.Add(first, second);
            secondToFirst.Add(second, first);
        }

        public TSecond this[TFirst first]
        {
            get { return GetByFirst(first); }
        }

        public TFirst this[TSecond second]
        {
            get { return GetBySecond(second); }
        }

        public TSecond GetByFirst(TFirst first)
        {
            return firstToSecond[first];
        }

        public TFirst GetBySecond(TSecond second)
        {
            return secondToFirst[second];
        }

        public IEnumerator GetEnumerator()
        {
            return GetFirstEnumerator();
        }

        public IEnumerator GetFirstEnumerator()
        {
            return firstToSecond.GetEnumerator();
        }

        public IEnumerator GetSecondEnumerator()
        {
            return secondToFirst.GetEnumerator();
        }
    }
}

Not the answer you're looking for? Browse other questions tagged or ask your own question.