482

I have an enum with Description attributes like this:

public enum MyEnum
{
    Name1 = 1,
    [Description("Here is another")]
    HereIsAnother = 2,
    [Description("Last one")]
    LastOne = 3
}

I found this bit of code for retrieving the description based on an Enum

public static string GetEnumDescription(Enum value)
{
    FieldInfo fi = value.GetType().GetField(value.ToString());

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

    if (attributes != null && attributes.Any())
    {
        return attributes.First().Description;
    }

    return value.ToString();
}

This allows me to write code like:

var myEnumDescriptions = from MyEnum n in Enum.GetValues(typeof(MyEnum))
                         select new { ID = (int)n, Name = Enumerations.GetEnumDescription(n) };

What I want to do is if I know the enum value (e.g. 1) - how can I retrieve the description? In other words, how can I convert an integer into an "Enum value" to pass to my GetDescription method?

davekaro
  • 6,233
  • 4
  • 28
  • 22

5 Answers5

439
int value = 1;
string description = Enumerations.GetEnumDescription((MyEnum)value);

The default underlying data type for an enum in C# is an int, you can just cast it.

Nicholas Piasecki
  • 25,203
  • 5
  • 80
  • 91
142

Update

The Unconstrained Melody library is no longer maintained; Support was dropped in favour of Enums.NET.

In Enums.NET you'd use:

string description = ((MyEnum)value).AsString(EnumFormat.Description);

Original post

I implemented this in a generic, type-safe way in Unconstrained Melody - you'd use:

string description = Enums.GetDescription((MyEnum)value);

This:

  • Ensures (with generic type constraints) that the value really is an enum value
  • Avoids the boxing in your current solution
  • Caches all the descriptions to avoid using reflection on every call
  • Has a bunch of other methods, including the ability to parse the value from the description

I realise the core answer was just the cast from an int to MyEnum, but if you're doing a lot of enum work it's worth thinking about using Unconstrained Melody :)

sclarke81
  • 1,739
  • 1
  • 18
  • 23
Jon Skeet
  • 1,421,763
  • 867
  • 9,128
  • 9,194
  • Isn't "value" an int? So, doesn't Enums.GetDescription((MyEnum)value) just cast the int to MyEnum? – davekaro Apr 16 '10 at 12:20
  • @davekaro: It casts the int to MyEnum - but you wouldn't be able to call it with any non-enum, including an "Enum" reference. Basically it's like your code, but with some generics magic. – Jon Skeet Apr 16 '10 at 13:06
  • 2
    @JonSkeet I don't see this method in Enums.cs in https://code.google.com/p/unconstrained-melody/downloads/detail?name=UnconstrainedMelody-0.0.0.2-src.zip&can=2&q= – tom Sep 13 '13 at 19:14
  • 2
    @tom: It may not be in the latest "released" version, but it's in the source: https://code.google.com/p/unconstrained-melody/source/browse/trunk/UnconstrainedMelody/Enums.cs – Jon Skeet Sep 14 '13 at 08:15
  • @JonSkeet can I use it with ASP.Net Core 1.0 (which is required `.xproj` project)? I'm now using rc1 which allow me to use this package, but I'm afraid that rc2 will turn this feature off. – Alex Zhukovskiy May 27 '16 at 10:47
  • 1
    @AlexZhukovskiy: I suspect so, although I haven't tried. You may need to use `import="dnxcore450"` or whatever. When .NET Core 1.0 ships, I'll try to remember to update the package to ensure it works with netstandard1.0. – Jon Skeet May 27 '16 at 10:48
  • @JonSkeet well, I'l give it a try :) – Alex Zhukovskiy May 27 '16 at 11:01
  • @JonSkeet this link returns a 404 – JsonStatham Jul 11 '17 at 14:40
  • @JsonStatham: Fixed to point to the location on github. – Jon Skeet Jul 11 '17 at 14:50
118

I put the code together from the accepted answer in a generic extension method, so it could be used for all kinds of objects:

public static string DescriptionAttr<T>(this T source)
{
    FieldInfo fi = source.GetType().GetField(source.ToString());

    DescriptionAttribute[] attributes = (DescriptionAttribute[])fi.GetCustomAttributes(
        typeof(DescriptionAttribute), false);

    if (attributes != null && attributes.Length > 0) return attributes[0].Description;
    else return source.ToString();
}

Using an enum like in the original post, or any other class whose property is decorated with the Description attribute, the code can be consumed like this:

string enumDesc = MyEnum.HereIsAnother.DescriptionAttr();
string classDesc = myInstance.SomeProperty.DescriptionAttr();
Irish
  • 1,407
  • 1
  • 10
  • 9
  • 6
    string classDesc = myInstance.SomeProperty.DescriptionAttr(); That will not work! Let say you have class Test { public int TestInt {get; set;} }. So if you will call new Test().TestInt.DescriptionAttr() you will get null reference exception - 0.GetType().GetField("0") – Vladimirs Dec 12 '13 at 13:34
36

To make this easier to use, I wrote a generic extension:

public static string ToDescription<TEnum>(this TEnum EnumValue) where TEnum : struct
{
    return Enumerations.GetEnumDescription((Enum)(object)((TEnum)EnumValue));
}

now I can write:

        MyEnum my = MyEnum.HereIsAnother;
        string description = my.ToDescription();
        System.Diagnostics.Debug.Print(description);

Note: replace "Enumerations" above with your class name

David
  • 1,743
  • 1
  • 18
  • 25
9

You can't easily do this in a generic way: you can only convert an integer to a specific type of enum. As Nicholas has shown, this is a trivial cast if you only care about one kind of enum, but if you want to write a generic method that can handle different kinds of enums, things get a bit more complicated. You want a method along the lines of:

public static string GetEnumDescription<TEnum>(int value)
{
  return GetEnumDescription((Enum)((TEnum)value));  // error!
}

but this results in a compiler error that "int can't be converted to TEnum" (and if you work around this, that "TEnum can't be converted to Enum"). So you need to fool the compiler by inserting casts to object:

public static string GetEnumDescription<TEnum>(int value)
{
  return GetEnumDescription((Enum)(object)((TEnum)(object)value));  // ugly, but works
}

You can now call this to get a description for whatever type of enum is at hand:

GetEnumDescription<MyEnum>(1);
GetEnumDescription<YourEnum>(2);
itowlson
  • 73,686
  • 17
  • 161
  • 157
  • How is "GetEnumDescription(1);" any better than GetEnumDescription((MyEnum)1); ? – davekaro Apr 16 '10 at 02:09
  • 1
    @davekaro: Implemented like this, it's not all that much better, but a more robust implementation based on generics could do this without the explicit cast, so you don't risk unhandled exceptions if the number doesn't actually match any of the enum values. – Aaronaught Apr 16 '10 at 02:15
  • 1
    Interesting. Just to clarify for future readers: One is not going to get an unhandled exception on an explicit cast if the number doesn't match one of the enum values (you could say "MyEnum value = (MyEnum)5;" and that line will execute just fine, but you would bomb in the first line of GetEnumDescription() as implemented in the original question (because GetField() will return null as it can find no matching field with that value). (To guard against that, we'd need to check Enum.IsDefined() first and return null or an empty string, or just throw an ArgumentOutOfRangeException ourselves.) – Nicholas Piasecki Apr 16 '10 at 02:48